简体   繁体   中英

Spring boot - setters on session scoped component not working from singleton service - fields are null

I have a simple service behind a REST controller in Spring Boot. The service is a singleton (by default) and I am autowiring a session-scoped bean component used for storing session preferences information and attempting to populate its values from the service. I call setters on the autowired component, but the fields I am setting stay null and aren't changed.

Have tried with and without Lombok on the bean; also with and without implementing Serializable on FooPref; also copying properties from FooPrefs to another DTO and returning it; also injecting via @Autowired as well as constructor injection with @Inject. The fields stay null in all of those cases.

Running Spring Boot (spring-boot-starter-parent) 1.5.6.RELEASE, Java 8, with the spring-boot-starter-web.

Session-scoped component:

@Component
@SessionScope(proxyMode = ScopedProxyMode.TARGET_CLASS)
@Data
@NoArgsConstructor
public class FooPrefs implements Serializable {
    private String errorMessage;
    private String email;
    private String firstName;
    private String lastName;
}

REST Controller:

@RestController
@RequestMapping("/api/foo")
public class FooController {

    @Autowired
    private FooPrefs fooPrefs;

    private final FooService fooService;

    @Inject
    public FooController(FooService fooService) {
        this.fooService = fooService;
    }

    @PostMapping(value = "/prefs", consumes = "application/json", produces = "application/json")
    public FooPrefs updatePrefs(@RequestBody Person person) {
        fooService.updatePrefs(person);

        // These checks are evaluating to true
        if (fooPrefs.getEmail() == null) {
            LOGGER.error("Email is null!!");
        }
        if (fooPrefs.getFirstName() == null) {
            LOGGER.error("First Name is null!!");
        }
        if (fooPrefs.getFirstName() == null) {
            LOGGER.error("First Name is null!!");
        }
        return fooPrefs;
    }
}

Service:

@Service
@Scope(value = "singleton")
@Transactional(readOnly = true)
public class FooService {

    @Autowired
    private FooPrefs fooPrefs;

    @Inject
    public FooService(FooRepository fooRepository) {
        this.fooRepository = fooRepository;
    }

    public void updatePrefs(Person person) {
        fooRepository.updatePerson(person);

        //the fields below appear to getting set correctly while debugging in the scope of this method call but after method return, all values on fooPrefs are null
        fooPrefs.setEmail(person.getEmail());
        fooPrefs.setFirstName(person.getFirstName());
        fooPrefs.setLastName(person.getLastName());
    }
}

I discovered my problem. Fields were being added to my FooPrefs session-managed object and were breaking my client. The setters were actually working and being nulled out by some error handling code.

Edits per below fixed the JSON serialization problems:

Session-scoped component (no change)

New Dto

@Data
@NoArgsConstructor
public class FooPrefsDto {
    private String errorMessage;
    private String email;
    private String firstName;
    private String lastName;
}

Controller (updated)

@RestController
@RequestMapping("/api/foo")
public class FooController {

    private final FooService fooService;

    @Inject
    public FooController(FooService fooService) {
        this.fooService = fooService;
    }

    @PostMapping(value = "/prefs", consumes = "application/json", produces = "application/json")
    public FooPrefsDto updatePrefs(@RequestBody Person person) {
        FooPrefsDto result = fooService.updatePrefs(person);

        // results coming back correctly now
        if (result.getEmail() == null) {
            LOGGER.error("Email is null!!");
        }
        if (result.getFirstName() == null) {
            LOGGER.error("First Name is null!!");
        }
        if (result.getFirstName() == null) {
            LOGGER.error("First Name is null!!");
        }
        return result;
    }
}

Service (updated)

@Service
@Scope(value = "singleton")
@Transactional(readOnly = true)
public class FooService {

    @Autowired
    private FooPrefs fooPrefs;

    @Inject
    public FooService(FooRepository fooRepository) {
        this.fooRepository = fooRepository;
    }

    public FooPrefsDto updatePrefs(Person person) {
        fooRepository.updatePerson(person);

        //the fields below appear to getting set correctly while debugging in the scope of this method call but after method return, all values on fooPrefs are null
        fooPrefs.setEmail(person.getEmail());
        fooPrefs.setFirstName(person.getFirstName());
        fooPrefs.setLastName(person.getLastName());
        return getFooPrefsDto();
    }

    private FooPrefsDto getFooPrefsDto() {
        FooPrefsDto retDto = new FooPrefsDto();
        retDto.setEmail(fooPrefs.getEmail());
        retDto.setLastName(fooPrefs.getLastName());
        retDto.setFirstName(fooPrefs.getFirstName());
        return retDto;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM