Jersey 2 with Jackson serialisation issue - jersey-2.0

Tools :
Weblogic 12c
Jersey 2.21.1
Jackson 2
public class Profile implements Serializable
{
private List<Status> orderStatus;
public void setOrderStatus(List<Status> orderStatus)
{
this.orderStatus = orderStatus;
}
public void getOrderStatus()
{
return orderStatus;
}
I have a simple POJO class as above.
I am facing below issue while using Jersey 2 with Jackson.
1)When Profile class is serialised , the JSON gets created as : {"OrderStatus":[{}]}
2)So the key generated is OrderStatus and not orderStatus
3)When this JSON gets de-serialised , it throws error -
Caused by: org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "OrderStatus" since it cannot
find field with OrderStatus but has field as orderStatus
I have tried adding :
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY,getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
hoping that serialisation will only use fields as a key (and will not use property) and JSON will be generated as {"orderStatus":[{}]} .
But it is not working and same error is thrown.
Is there any way we can serialise POJO with key as fields and not properties.
Can anybody please help here ?

If you want to make sure orderStatus is the name use specific JsonProperty :
#JsonProperty("orderStatus")
public void getOrderStatus()
#JsonProperty (also indicates that property is to be included) is used to indicate external property name

Related

How to query using fields of subclasses for Spring data repository

Here is my entity class:
public class User {
#Id
UserIdentifier userIdentifier;
String name;
}
public class UserIdentifier {
String ssn;
String id;
}
Here is what I am trying to do:
public interface UserRepository extends MongoRepository<User, UserIdentifier>
{
User findBySsn(String ssn);
}
I get an exception message (runtime) saying:
No property ssn found on User!
How can I implement/declare such a query?
According to Spring Data Repositories reference:
Property expressions can refer only to a direct property of the managed entity, as shown in the preceding example. At query creation time you already make sure that the parsed property is a property of the managed domain class. However, you can also define constraints by traversing nested properties.
So, instead of
User findBySsn(String ssn);
the following worked (in my example):
User findByUserIdentifierSsn(String ssn);

Custom error is not rendered as hal in Spring Boot 1.3 and Spring hateoas 0.19

Initially I used Spring Boot 1.2 and Spring hateoas in my project, and I need to customize error message. So I created our class instead of the native VndErrors and VndError.
I created a class extends VndErrors.VndError.
public class MyError extends VndErrors.VndError{
//add some my custom fields
}
And antoher class to wrap the MyError.
public class ErrorDetails{
int total;
#JsonProperty("_embedded")
Map<String, List<MyError>> errors;
public ErrorDetails(List<MyError> err){
this.total=err.size();
errors.put("errors", err);
}
}
All exception are hanleded in a #ContrllerAdvice class. I used a custom Jackson2ObjectMapperBuilder to configure ObjectMapper in our project.
When I used Spring 1.2, it was rendered as expected. As following.
{
"total": 1,
"_embedded":{
"errors":[
{
//feilds,
_links:{
"self":""
}
}
]
}
}
But when upgraded to Spring Boot 1.3, it does not work as excepted.
The _links rendered as links, and the content type is application/json in the debug info.
Stage 1:
I am trying to create a simple pojo with a List of Link, it does not work.
public class ErrorDetails{}//pojo includes fields
public class MyError{
//add some my custom fields
#JsonUnwrapped
ErrorDetails content;
List<link> links;
}
public class ErrorResources{
int total;
#JsonProperty("_embedded")
Map<String, List<MyError>> errors;
public ErrorResources(List<MyError> err){
this.total=err.size();
errors.put("errors", err);
}
}
I found some related issues on github of Spring Hateoas project.
https://github.com/spring-projects/spring-hateoas/issues/279
https://github.com/spring-projects/spring-hateoas/issues/324
https://github.com/spring-projects/spring-hateoas/issues/288
I tried one of the suggestions of the issues above, when added #JsonSerialze(using=Jackson2HalModule.HalLinkListSerializer) on links of MyError class.
Got message similar with can not find the correct HttpMessageConverter, the content type of result is application/ocect(binary).
I also tried set the default contentType or default viewResolver to MappingJackson2JsonView, all did not change the result.
Whend I added a custom MappingJackson2HttpMessageConverter in my config:
#Bean
#Order(1)
public MappingJackson2HttpMessageConverter jacksonMessageConverter() {
ObjectMapper halObjectMapper=ctx.getBean("_halObjectMapper", ObjectMapper.class);
MappingJackson2HttpMessageConverter jacksonMessageConverter =
new MappingJackson2HttpMessageConverter();
jacksonMessageConverter.setObjectMapper(halObjectMapper);
jacksonMessageConverter.setSupportedMediaTypes(
Arrays.asList(MediaTypes.HAL_JSON, MediaType.APPLICATION_JSON_UTF8, MediaType.ALL));
return jacksonMessageConverter;
}
The error result is rendered as expected. But I do not think it is the correct way, because I used MediaType.ALL here. And it caused another big problem.
I used TestRestTemplate to test my rest APIs. The restTemlate tried to treat the input data as XML. I saw in the exception it indicated it tried to invoke a XmlHttpMessageConverter to process the content(it is json), even I have set the accept header as application/json. Of course, before I upgraded to Spring Boot 1.3 stack, it worked.
Stage 2:
I tried to use Resources and Resource to wrap the error result.
public class ErrorDetails{}//pojo includes error description fields
public class ErrorResource extends Resource<ErrorDetails>{
}
public class ErrorResources extends Resources<ErrorResource>{
}
public class ErrorMessage {
int total;
ErrorResources errors;
}
Spring still can not render the error result as hal format, it is application/json. When I added
#JsonSerialze(using=Jackson2HalModule.HalResourcesSerializer) on ErrorResources class, it raised an exception which complained the HalResourcesSerializer does not has a default constructor.
In the #ControllerAdvice class, I have tried to set the method return type to ErrorMessage and a wrapper ResponseEntity , it does not work.
Finally, my question is how to render the response body in a #ControllerAdvice same as the one in a normal #RestController? Why it does not work in a #ControllerAdvice class?
Is there a simple workaroud for this issue?

GWT: com.google.gwt.user.client.rpc.SerializationException for Type 'java.util.HashMap$KeySet'

I am getting com.google.gwt.user.client.rpc.SerializationException exception for HashSet.
Initially I thought either HashSet of Long is not supported.
But https://developers.google.com/web-toolkit/doc/latest/RefJreEmulation contains both of these.
What would be the problem?
I am posting the Service method here:
public Set<Long> getNamesFromIDs(Set<Long> ids) {
return manager.getNamesFromIDs(ids);
}
Here, manager is the reference to the Manager class which is included from a library.
I am posting the manager method too:
public Set<Long> getNamesFromIDs(Set<Long> styleIds) {
List<Long> listIDs = new ArrayList<Long>(styleIds);
Map<Long, Discount> personMap = personDAO.getStyleIdToDiscountMap(listIDs, 0);
return personMap.keySet();
}
Detailed Exception Message:
com.google.gwt.user.client.rpc.SerializationException: Type 'java.util.HashMap$KeySet'
was not included in the set of types which can be serialized by this
SerializationPolicy or its Class object could not be loaded.
For security purposes, this type will not be serialized.: instance = [30002, 30001]
The above classes from java.util are serialized by the custom field serializer.
Serialization for the KeySet is not supported by GWT. It does not implement a Serializable interface ( so it is not serializable in java world either)

Spring List of interface type data binding - how?

Tried to find the answer on the Web but failed. Should be simple for pro Spring Devs... so here it comes:
In few words I want to bind the List of interface type: List to the form and get the data back (possibly modified by user via form. The problem is that it doesn't work :(
my code (short version) - command/model class which is passed to the form:
public class RoomsFormSearchResultCommand extends RoomsFormSearchCommand {
#SuppressWarnings("unchecked")
private List<IRoom> roomsList = LazyList.decorate(new ArrayList<Room>(),
FactoryUtils.instantiateFactory(Room.class));
public List<IRoom> getRoomsList() {
return roomsList;
}
public void setRoomsList(final List<IRoom> roomsList) {
this.roomsList = roomsList;
}
(...)
then in the form I use it like that (short version):
<form:form method="post" action="reserve" commandName="roomsResultsCmd">
(...)
<c:forEach var="room" items="${roomsResultsCmd.roomsList}"
varStatus="status">
<tr>
<td><form:input path="roomsList[${status.index}].roomNumber" readonly="true"/>
(...)
The form is displayed fine but after submitting it I get:
2012-01-22 21:31:55 org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [wyspa] in context with path [/wyspa] threw exception [Request processing failed; nested exception is org.springframework.beans.InvalidPropertyException: Invalid property 'roomsList[0]' of bean class [com.wyspa.controller.command.RoomsFormSearchResultCommand]: Illegal attempt to get property 'roomsList' threw exception; nested exception is org.springframework.beans.NullValueInNestedPathException: Invalid property 'roomsList' of bean class [com.wyspa.controller.command.RoomsFormSearchResultCommand]: Could not instantiate property type [com.wyspa.entity.IRoom] to auto-grow nested property path: java.lang.InstantiationException: com.wyspa.entity.IRoom] with root cause
org.springframework.beans.NullValueInNestedPathException: Invalid property 'roomsList' of bean class [com.wyspa.controller.command.RoomsFormSearchResultCommand]: Could not instantiate property type [com.wyspa.entity.IRoom] to auto-grow nested property path: java.lang.InstantiationException: com.wyspa.entity.IRoom
at org.springframework.beans.BeanWrapperImpl.newValue(BeanWrapperImpl.java:633)
at org.springframework.beans.BeanWrapperImpl.growCollectionIfNecessary(BeanWrapperImpl.java:863)
at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:770)
at org.springframework.beans.BeanWrapperImpl.getNestedBeanWrapper(BeanWrapperImpl.java:555)
(...)
The deal is then when I change the List to "instances" list everything works fine!
public class RoomsFormSearchResultCommand extends RoomsFormSearchCommand {
#SuppressWarnings("unchecked")
//notice that the List is now List<Room>
private List<Room> roomsList = LazyList.decorate(new ArrayList<Room>(),
FactoryUtils.instantiateFactory(Room.class));
In this case data is passed to the controller in proper way.
Since I am used to devlop on interfaces and I am pretty crazy about it I would REALLY prefer not to translate the List<IRoom> (which comes back from services) to List<Room> which seems to suit Spring. Is it possible to work with List<IRoom> in this case or Spring just doesn't support it?
//Of course Room implements IRoom - but I guess you already got that...
I would be VERY happy for any help/suggestions!
Best Regards,
Nirwan
I have exact the same problem. Changing to following won't fix the problem. It looks spring binding ignores the factory utils and tries to instantiate the null object itself:
#SuppressWarnings("unchecked")
private List<IRoom> roomsList = LazyList.decorate(new ArrayList<IRoom>(),
FactoryUtils.instantiateFactory(Room.class));
The workaround is to set auto grow nested path off in your controller:
#InitBinder protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
binder.setAutoGrowNestedPaths(false);
super.initBinder(request, binder);
}
The problem is you'll lose the handy nested path like user.account.address.street. You have to make sure none of user, account, addresss is null. It does cause a lot of problems. That's why I came here, see if I can find better solution.
If you don't actually need the list to auto-grow, you can store the form object in the session to avoid the nasty side effects of disabling auto-growing nested paths.
#Controller
#SessionAttributes(types = RoomsFormSearchResultCommand.class)
public final class SearchController {
#InitBinder
protected void initBinder(final WebDataBinder binder) {
binder.setAutoGrowNestedPaths(false);
}
#RequestMapping(method = RequestMethod.GET)
public String showForm(final Model model) {
RoomsFormSearchResultCommand form = ... // create or load form
model.addAttribute(form);
}
#RequestMapping(method = RequestMethod.POST)
public String onSubmitUpdateCart(
#ModelAttribute final RoomsFormSearchResultCommand form,
final BindingResult result,
final SessionStatus status) {
// if result has no errors, just set status to complete
status.setComplete();
}
}
Try the following lines
#SuppressWarnings("unchecked")
private List<IRoom> roomsList = LazyList.decorate(new ArrayList<IRoom>(),
FactoryUtils.instantiateFactory(Room.class));
don't have time to try that myself, but it would make sense.

Jersey Marshall Map<Date,List>

I start understanding how jersey works with JAXB. But today i faced a particular case where i want to marshall a Map of (Date,List) entries:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class MyClass{
#XmlJavaTypeAdapter(MapAdapter.class)
private Map<Date,List<MyObject>> = new TreeMap<Date,List<MyObject>>(new DateCompareDesc());
}
The goal here is to marshall a Map whose entry is a Date with its corresponding list of MyObject. the map is sorted in desc order.
For this i implemented an Adapter for Map (MapAdapter, following #Blaise Doughan's tutorial, http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html). The problem is on the Date key. I have an Error : Unable to marshall java.util.Date. So i tried this new Date Adapter :
public class DateAdapter extends XmlAdapter<String, Date> {
#Override
public Date unmarshal(String v) throws Exception {
//not implemented
}
#Override
public String marshal(Date v) throws Exception {
return v.toString();
}
}
Where can i add #XmlJavaTypeAdapter(DateAdapter.class) so that Jersey could marhsall Date as key to my TreeMap?
Thanks.
JAXB supports the marshalling/unmarshalling of java.util.Date to the standard XML schema types: date, time, dateTime. You can control the type used with the #XmlSchemaType annotation.
http://blog.bdoughan.com/2011/01/jaxb-and-datetime-properties.html
If your date information is not represented as one of the standard XML schema types, you can use an XmlAdapter similar to the one I used the following answer to a similar question:
jaxb unmarshal timestamp
If you need to use the XmlAdapter approach, the #XmlJavaTypeAdapter annotation would be placed on the Date field of the adapted object representing the entry in the Map. Below is what this might look like based on my blog: http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html.
import javax.xml.bind.annotation.XmlValue;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
public class MyMapEntryType {
#XmlAttribute
#XmlJavaTypeAdapter(DateAdapter.class)
public Date key;
public List<MyObject> value;
}