Spring java syntax error - spring

I have a self join class where I want to save a parent object along with the children. To implement that I have:
Model
public class UserEntity implements Serializable {
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name="checker_id")
private UserEntity checker;
#OneToMany(mappedBy="checker", orphanRemoval=true, cascade = CascadeType.ALL)
private Set<UserEntity> setters = new HashSet<UserEntity>();
// getter and setter
public void addSetter(UserEntity setter) {
if(setters == null) {
setters = new HashSet<UserEntity>();
}
setter.setChecker(this);
this.setters.add(setter);
}
This is the DAO
public UserEntity create(UserEntity checker){
List<UserEntity> list = new ArrayList();
for(UserEntity setter : list)
checker.addSetter(setter);
if (checker != null)
sessionFactory.getCurrentSession().persist(checker);
return checker;
I get the error
Syntax error on token "(", Expression expected after this token
at this line
for(UserEntity setter : List<UserEntity>())
I would appreciate knowing what is missing in the DAO code.

It should be like that
List<UserEntity> list = ...
for(UserEntity setter : list)

Related

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;
}
}

Hibernate -validator group sequence provider getDefaultSequenceProvider gets null as input

I am using the hibernate validator group sequence and want to execute the groups in a sequence based on business rules. But the input to the groupSequenceProvider for its getValidationGroups is always null, and hence custom sequence never gets added.
My request object:
#GroupSequenceProvider(BeanSequenceProvider.class)
public class MyBean {
#NotEmpty
private String name;
#NotNull
private MyType type;
#NotEmpty(groups = Special.class)
private String lastName;
// Getters and setters
}
Enum type:
public enum MyType {
FIRST, SECOND
}
My custom sequence provider:
public class BeanSequenceProvider implements DefaultGroupSequenceProvider<MyBean> {
#Override
public List<Class<?>> getValidationGroups(MyBean object) {
final List<Class<?>> classes = new ArrayList<>();
classes.add(MyBean.class);
if (object != null && object.getType() == MyType.SECOND) {
classes.add(Special.class);
}
return classes;
}
}
Group annotation:
public interface Special {
}
When I execute the above code, I get the input MyBean object as null and cannot add the custom sequence. What am I missing? I am using hibernate-validator version as 5.4.1.Final

Avoidy Lazy Initialization except in dozer mapping for null collections

#Override
RegistrationDto isCandidateUnfit(RegistrationDto dto) {
Long nationId = 0L;
if(dto.getNationMast() != null){
nationId = dto.getNationMast().getNationId();
}
Registration reg = registrationRepo.findCandidateMedicalStatus(dto.getPassportNo(),nationId,
dto.getCivilId(), ServiceConstants.CANDIDATE_MED_STATUS_UNFIT_ID);
return getMapper().map(reg, RegistrationDto.class) ;
}
While mapping the doing dozer mapping if one caollection(appointments) is null, it throw exception failed to lazily initialize a collection of role: om.gov.moh.model.cdc.Registration.appointments
It can't be changed from Lazy to eager
//RegistrationDto
#SuppressWarnings("serial")
public class RegistrationDto extends SearchDto implements java.io.Serializable {
// Fields
private Long regId;
#JsonIgnore
private Set<AppointmentDto> appointments = new HashSet<>(0);
private String orderStatus;
/** setters & getters **/
}
You have the possibility to create custom converters as shown here.
Create a custom converter and when you have an uninitialized collection, just set it to null or empty. You can do the check with Hibernate.isInitiliazed(Object proxy). Reference here.

How to send Java collections containing subclasses to spring controller

I'm trying to send collections to my spring MVC controller:
#RequestMapping("/postUsers.do")
public #ResponseBody ResponseDTO postUsers(#ModelAttribute("mapperList") MapperList mapperList) {
//prints {"users":null}
System.out.println(new ObjectMapper().writeValueAsString(mapperList));
return new ResponseDTO();
}
this is the code posting my users :
public ResponseDTO postUsers(ArrayList<User> users) {
ResponseDTO serverResponse = null;
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestMethod("POST");
// prints {"users":[{"property1":"x","property1":y}]}
System.out.println(objectMapper.writeValueAsString(new MapperList(users)));
objectMapper.writeValue(connection.getOutputStream(), objectMapper.writeValueAsString(new MapperList(users)));
//blabla ...
}
and this is the object containing my list :
public class MapperList implements Serializable {
private static final long serialVersionUID = 8561295813487706798L;
private ArrayList<User> users;
public MapperList() {}
public MapperList(ArrayList<User> users) {
this.setUsers(users);
}
public ArrayList<User> getUsers() {
return users;
}
public void setUsers(ArrayList<User> users) {
this.users = users;
}
}
and this is the users type to post:
public abstract class User implements Serializable {
private static final long serialVersionUID = -1811485256250922102L;
private String property1;
private String property2;
public User() {}
public User(String prop1, String prop2) {
// set properties
}
// getters and setters
}
the problem is, when I output the value of the users's array before to post it to the controller, I got the following json value :
{"users":[{"property1":"x","property1":y}]}
but in the controller, when I print what I get from the request body, I only get :
{"users":null}
I also tryed with the annotation #RequestBody instead of #ModelAttribute("mapperList") and a JSONException is displayed :
*A JSONObject text must begin with '{' at 1 [character 2 line 1]\r\n*
My array list of users contains only one user that should be displayed. I don't understand why this doesn't work...
Thanks for any help !
You can chnage your MapperList class definition as public class MapperList extends ArrayList<User>{ ..} you dont need to define any instance variable like private ArrayList users inside MapperList class. Use #Requestbody annotation. You will be able to use MapperList as a ArrayList
Try to use:
public class MapperList{
private List<User> users;
//setter and getter
//toString
}
public class User{
private String property1;
private String property2;
//getter + setter
}
json:
{"users":[{"property1":"x", "property2":"y"}]}
in controller use #RequestBody. In that case Jackson will map your json to ArrayList of users.
#ResponseStatus(HttpStatus.OK)
#RequestMapping("/postUsers.do")
public #ResponseBody ResponseDTO postUsers(#RequestBody MapperList users) {
System.out.println(users);
return null;
}
no need to get objectMapper in that case. Don't forget to set content-type in request header to application/json. It required by Spring to handle #RequestBody processing.
If not working try to change MapperList:
List<User> users = new ArrayList<User>();
On the server side keep the #RequestBody annotation:
public #ResponseBody ResponseDTO postUsers(#RequestBody MapperList mapperList)
...
But this line causes problems:
objectMapper.writeValue(
connection.getOutputStream(),
objectMapper.writeValueAsString(new MapperList(users))
);
First it converts the object to JSON and then again uses objectMapper to JSON-encode the string into output stream. Try the following instead:
connection.getOutputStream().write(
objectMapper.writeValueAsString(new MapperList(users))
.getBytes("UTF-8")
);
or directly output to stream:
objectMapper.writeValue(
connection.getOutputStream(),
new MapperList(users))
);
Zbynek gave me part of the answer. Indeed
objectMapper.writeValue(
connection.getOutputStream(),
objectMapper.writeValueAsString(new MapperList(users))
);
doesn't work properly in my case
But moreover, my User class was an abstract class, with many type of User as subclasses. so the #RequestBody annotation couldn't work without specified the object type in the Json.
I used the following annotations on User class to make it working :
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = SubClassA.class, name = "a"),
#JsonSubTypes.Type(value = SubClassB.class, name = "b")
})
Thanks a lot for all your answers.

LazyInitializationException in AOP logger aspect

I have an app build with Spring, JSF JPA and Hibernate.
I have an aspect that "watches" every update*, create*,delete* method from my service layer of the application. This aspect logs the method params, apply toString to every param and them log them in the database. The problem is that I use domain objects in jsf and when i try to update* something i get a LazyInitializationException when toString() is applied to the method param.
One solution would be to remove from toString all params that represents other objects but then the operation has no sense as i do not log the details that interests me.
ie. I have an entity called Price which has a dependency PriceList:
public class Price extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "price")
private Double price;
//bi-directional many-to-one association to TelCoPriceList
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "price_list_id")
private PriceList priceList;
.....................
}
And the price is used into AddPriceForm.xhtml, which is the jsf form. The JSF AddPriceMB has a reference to PriceService which performs the actual update.
The PriceService is "monitored" by this aspect:
#Aspect
#Named("auditLogAspectImpl")
public class AuditLogAspectImpl implements AuditLogAspect {
#Inject
private UserService userService;
#Inject
private AuditLogService auditLogService;
#Override
#AfterReturning(pointcut = "execution(* com.videanuadrian.core.impl.services..*.save*(..)) or execution(* com.videanuadrian.core.impl.services..*.update*(..)) or execution(* com.videanuadrian.core.impl.services..*.delete*(..))", returning = "retVal")
public boolean afterLogEvent(JoinPoint joinPoint,Object retVal) {
String className = joinPoint.getTarget().getClass().getName();
String methondName = joinPoint.getSignature().getName();
...................................................................
StringBuffer logMessage = new StringBuffer();
Object[] args = joinPoint.getArgs();
//for login action we only get the username and hash the password
if (methondName.compareTo("login") == 0){
logMessage.append(args[0]);
}else {
int argsLen = args.length;
//else log all the parameters
for (int i = 0; i < argsLen; i++) {
// this is where the exception occurs !!!!!!!!!!!!!!!!!!!!!!!!!!!
logMessage.append(args[i]).append(",");
}
if (argsLen > 0) {
logMessage.deleteCharAt(logMessage.length() - 1);
}
}
//some save/update methods return Boolean
Boolean status = false;
if (retVal instanceof Boolean){
status = (Boolean) retVal;
}
//some return the ID of the object inserted,and if these methods return an integer the status is true, if they return null, the status si false
if (retVal instanceof Integer){
if (retVal!=null)
status = true;
}
auditLogService.addAuditLogEvent(uid, className+"."+methondName, status,logMessage.toString());
return true;
}
On a prior version I did not had this problem because I had used DTO objects and the conversion between DTO and Domain Objects was performed in the service layer. The error is very clear, as my session was closed long ago compared to the time that I perform this toString() operation.
Any idea how can i achieve this without using openSessionInView or extended persistence context? Or maybe my approach is not good....

Resources