Fasterxml jackson polymorphism error - java

I'm using wildfly with resteasy + jackson and I've created a super abstract class named Participation, a subclass InnovationParticipation and a simple rest service. Here is the code:
//Super abstract class
#JsonTypeInfo(use=Id.NAME, property="theType", include = JsonTypeInfo.As.PROPERTY)
#JsonSubTypes({
#JsonSubTypes.Type(value=InnovationParticipation.class, name="innovation"),
})
public abstract class Participation implements Serializable {
private static final long serialVersionUID = -8008289902553477716L;
private String type;
private String groupName;
private String groupEmail;
//Constructor, getters and setters
}
//subclass
public class InnovationParticipation extends Participation {
private static final long serialVersionUID = -2843212924880669778L;
private String area;
private String innovationType;
private String title;
private String ideaDescription;
//Constructor, getters and setters
}
//rest request
public class ParticipationRequest implements Serializable {
private static final long serialVersionUID = -8919114519349685945L;
private Participation participation;
}
//rest method
#POST
#Path("/participate")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public ParticipationResponse participate(ParticipationRequest request) {
System.out.println("Yuppiiiii");
}
But Wildfly returns this error:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of beans.Participation, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
at [Source: io.undertow.servlet.spec.ServletInputStreamImpl#dd39841; line: 1, column: 18] (through reference chain: webservices.requests.ParticipationRequest["participation"])
Can anyone try to solve my problem?
Thanks in advance

Related

MongoDB spring repository - abstract class as field "Class is abstract"

I'm getting error when spring mongo template reading object from DB: "Class is abstract". This is because internal field in document is abstract type.
in my case classes looks like:
public abstract class Context {
private String name;
}
public class AContext {
private String aData;
}
public class BContext {
private String bData;
}
#Document
#TypeAlias("Task")
public class Task {
#Id
private String id;
private String name;
private List<Context> contexts;
}
How can I fix thiss issue ?

JSON to java object returing LinkedHashMap

I have below json string :-
{"name":"Test","sortlist":[],"filterlist":[{"fieldname":"regions_id","operator":"equals","value":{"id":1,"code":"HIGH","description":"HIGH Region","comment":"High Region","active":true}}]}
and Java class as below :-
#JsonSerialize
#JsonDeserialize
public class ItemFilter implements Serializable {
private String name;
private List<FieldFilter> filterlist = new ArrayList<FieldFilter>();
}
public class FieldFilter implements Serializable {
private static final long serialVersionUID = 1L;
private String fieldname;
private String operator;
private Object value;
}
and my convert method as below :-
public static ItemFilter convertItemFilter(String item) {
ObjectMapper mapper = new ObjectMapper();
try {
ItemFilter itemFilter = mapper.readValue(item, new TypeReference<ItemFilter>(){});
return itemFilter;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
ItemFilter domain is getting converted correctly but in private Object value; field i am getting LinkedHashMap i want to get an simple object and later i will type cast it.
Can someone please guide me how to escape LinkedHashMap and get an simple Java Object in variable?
i cant use hard coding Object type because its a generic pojo which can have any object type. hard coding will make this pojo very bigger and frontend also need to change for it. So that why i have used Object as data type.
The following class structure should return the JSON to "YourObject"
public class YourObject{
private String name;
private List<String> sortList;
private List<Filter> filterList;
public static class Filter{
private String fieldname;
private String operator;
private Value value;
}
public static class Value{
private Integer id;
private String code;
private String description;
private String comment;
private Boolean active;
}
}
Then use the following to read it into the object:
YourObject itemFilter = mapper.readValue(item, YourObject.class);

How to deserialize a generic object at runtime with Jackson

Say I have the following java classes (getters & setters omitted for brevity).
public class AllMyEvents {
private List<SomeEvent<?>> eventList;
}
public class SomeEvent<T> {
private long time;
#JsonProperty("event_type")
private String eventType;
#JsonProperty("event_data")
private T eventData;
}
public class BigEvent {
private List<SomeEvent<LittleEvent>> subEvents;
}
public class LittleEvent {
private long data;
}
When I call:
ObjectMapper om = new ObjectMapper();
AllMyEvents events = om.readValue(IOUtils.toString(jsonData, "UTF-8"),AllMyEvents.class);
The field eventData is of type LinkedHashMap. What I want is for this fields type to be specified by the eventType string. If the string is 'big' I want eventData to have type BigEvent or LittleEvent if the string is 'little'.
Is it possible to do this with Jackson annotations, or will I need to write a custom serializer/deserializer, or some other method? I'm using Jackson 1.9 if that is relevant.
Json Sub types is your answer.
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="#class")
#JsonSubTypes({
#JsonSubTypes.Type(value=BigEvent.class, name="big"),
#JsonSubTypes.Type(value=LittleEvent.class, name="little")
})
public class SomeEvent<T> {
private long time;
#JsonProperty("event_type")
private String eventType;
...
Also see: http://wiki.fasterxml.com/JacksonPolymorphicDeserialization

REST API with Interfaces - JAXB

I am using an implementation of an interface in Java.
For eg: There can be many PaymentTypes like Credit Card, Mobile etc.
I am making a REST API which contains an interface- how do I map this in JAXB, currently it gives me JAXBException occurred : 2 counts of IllegalAnnotationExceptions.
Currently I am using Apache-CXF and JAXb
#XmlRootElement
public class Payment {
#XmlElement
private PaymentType paymentType;
#XmlElement
private long price;
public Payment() {
}
public Payment(final PaymentType paymentType, final long price) {
super();
this.paymentType = paymentType;
this.price = price;
}
}
#Path("/trial")
public class TrialService {
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Payment> getPayments() {
final List<Payment> payments = new LinkedList<Payment>();
final CreditCardDetails creditCard = new CreditCardDetails(
"8767798778", "123", 12, 2016);
final Payment payment = new Payment(creditCard, 10);
payments.add(payment);
return payments;
}
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public PaymentDetails startPayment(final PaymentDetails paymentDetails) {
return paymentDetails;
}
}
public class CreditCardDetails implements PaymentType {
#XmlElement
private String creditCardNumber;
#XmlElement
private String cvv;
#XmlElement
private int expirationMonth;
#XmlElement
private int expirationYear;
public CreditCardDetails() {
}
#SuppressWarnings("javadoc")
public CreditCardDetails(
// final BillingAddress billingAddress,
final String creditCardNumber, final String cvv,
final int expirationMonth, final int expirationYear) {
super();
this.creditCardNumber = creditCardNumber;
this.cvv = cvv;
setExpirationMonth(expirationMonth);
setExpirationYear(expirationYear);
}
}
How should I be mapping this or should I be using an entirely different approach?
Edits:
For the POST method I am receiving a payment. Payment could contain any object CreditCard, Wallet etc. What annotation should I provide so that it is desirialized correctly.
Currently it throws a JAXB exception.
The full error message which you've got is:
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions PaymentType is an interface, and JAXB can't handle interfaces.
You need to use concreate class for your elements or point it in type attribute of #XmlElement annotation:
#XmlElement(type = CreditCardDetails.class)
private PaymentType paymentType;
If you have more classes that uses PaymentType interface then you may use the following solution:
#XmlAnyElement
#XmlElementRefs({
#XmlElementRef(type=CreditCardDetails.class),
#XmlElementRef(type=Wallet.class)
})
PaymentType paymentType;
The list of #XmlElementRefs can have any number of elements but all possibilities must be listed. CreditCardDetails and Wallet must be annotated with #XmlRootElement.
You can skip #XmlElementRefs annotation:
#XmlAnyElement(lax=true)
PaymentType paymentType;
but in that case make sure you have any required class in JAXB context, if you do not use registry annotate your class with PaymentType field with #XmlSeeAlso({CreditCardDetails.class, Wallet.class}).

In Json: What exactly is a "direct self-reference"

The question may seems stupid, but for me a cycle reference is for example the object A refers an object B AND the object B refers the object A.
I am working with on a android application communicating with a GAE server with objectify DB.
My model is quite simple but I get a error:
org.codehaus.jackson.map.JsonMappingException: Direct self-reference leading to cycle (through reference chain: java.util.ArrayList[0]->com.my.model.MyMessage["senderKey"]->com.googlecode.objectify.Key["root"])
Here is my model: a MyMessage refers a MyUser (the MyUser DOESNT refer a MyMessage...
Here is the code:
public class MyMessage implements Serializable {
private static final long serialVersionUID = -1075184303389185795L;
#Id
private Long id;
#Unindexed
private String sendMessage;
#Unindexed
private String answerMessage;
private MessageStatus status = MessageStatus.FREE;
#Parent
Key<MyUser> senderKey;
Key<MyUser> answererKey;
#SuppressWarnings("unused")
private MyMessage() {
}
public MyMessage(MyUser user, String message) {
super();
this.sendMessage = message;
this.senderKey = new Key<MyUser>(MyUser.class, user.getId());
}
[... getters and setters ...]
}
.
public class MyUser implements Serializable {
private static final long serialVersionUID = 7390103290165670089L;
#Id private String id;
#SuppressWarnings("unused")
private MyUser() {
this.setId("default");
}
public MyUser(String mail) {
this.setId(mail);
}
public void setId(String mail) {
this.id = mail;
}
public String getId() {
return id;
}
}
So what is exactly a Direct self-reference ?? What is wrong with my model??
Thank you.
Key internally contains reference to parent Key, this is type-wise a reference to iteslf, i.e. a direct self-reference. This could potentially lead to endless loop, so Jackson is throwing an error.
Bottom line: Key is not serializable out-of-the-box. You might get by by writing a custom Jackson serializer/deserializer.

Categories