I have parent class on which I have specified a custom deserialiser like this -
#JsonDeserialize(using = CustomDeserializer.class)
public class ParentClass {
}
I have subclasses extending above class and I don't want those classes to use CustomDeserializer for deserialisation purpose. I know using Will ignore the CustomDeserializer class during serialisation.
#JsonDeserialize(as = Child.class)
public class ChildClass extends ParentClass {
}
The question is - Is there any other way to tell ObjectMapper or anything else which will ignore this CustomDeserializer without specifically specifying #JsonDeserialize(as = Child.class) on every child class ?
Remove the annotation from the ParentClass and create a new subclass with the annotation. Use this new subclass when you want to deserialize to a ParentClass. As the custom deserialize annotation is on the subclass you can return an instance of ParentClass.
public class ParentClass {
// fields in the ParentClass
}
#JsonDeserialize(using = CustomDeserializer.class)
public class ParentWithCustomDeserialize extends Parent {
}
Then you can simply...
Parent parent = objectMapper.readValue(jsonString, ParentWithCustomDeserialize.class);
Related
I need to deserialize a JSON to a Java class with a Serializable field.
In the following Java class the value field is an interface, the idea is that the view can send values of types: String, Double, Long and ArrayList. If I change the type of value field from Serializable to Object, it works as expected.
public class UpdateAttribute implements Serializable {
//..
// There is something like: #JsonImplType(Object.class)
private Serializable value;
}
My question is, there is such a way to define a default class type to the value field? Something like: #JsonImplType(Object.class)?
The solution to this problem is use an annotation from jackson-databind module.
A similiar question was asked here: Jackson - How to specify a single implementation for interface-referenced deserialization?.
public class UpdateAttribute implements Serializable {
//..
#JsonDeserialize(as = Object.class)
private Serializable value;
}
However, there is a detail to be considered. The setValue method of UpdateAttribute can't be declared with a Serializable argument. Because Jackson don't know about the casting from Object to Serializable. Therefore, the final class should look like:
public class UpdateAttribute implements Serializable {
#JsonDeserialize(as = Object.class)
private Serializable value;
public void setValue(Object value) {
this.value = (Serializable) value;
}
}
In my Spring boot service, I have a controller as below
#PostMapping
public ApiResponse generateUKLabel(#RequestBody LabelRequestData data){
//do operation
}
Here, LabelRequestData has List of base class.
In, request I am passing child class data with base class data.
But, Child class data seems to be ignored.
Is there any way I can access the child class data.
I want to make the LabelRequestData with Base class generic so that it can accept multiple child class data.
Is there any way to solve it?
I tried casting. but throws can't cast exception
I also tried generics. but then I need to create two controller method to handle those request. I want only one controller method to handle the request
#Data
public class LabelRequestData extends BaseRequestData {
#Valid
private List<BaseClass> labelData; // this base class has multiple child classes that i need
#Valid
private PreferenceData preferenceData;
}
When Deserialising the Jackson will not know which child class that has to be used, so it only takes the value of the BaseClass and ignores the ChildClass
You could use #JsonTypeInfo in the BaseClass , this helps the Jackson to identify the proper ChildClass (You have to add type in the json)
I am not sure what BaseClass holds so I am just assuming random attributes below.
BaseClass.java
#Data
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = ChildOne.class, name = "childOne"),
#JsonSubTypes.Type(value = ChildTwo.class, name = "childTwo")})
public class BaseClass {
private Integer id;
}
ChildOne .java
#Data
public class ChildOne extends BaseClass {
private String name;
}
ChildTwo.java
#Data
public class ChildTwo extends BaseClass {
private String address;
}
If you request the Json,
{
"labelData": [
{
"id": 0, // -|
"type": "childOne", // |-> This will go to ChildOne.class
"name": "Foo" // _|
}, {
"id": 0, // -|
"type": "childTwo", // |-> This will go to ChildTwo.class
"address": "Somewhere in Earth"// _|
}
]
// Rest of Json
}
Problem:
Fasterxml can construct an object when it use abstraction in setters. See code below
Can not construct instance of CarState, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
Code:
#MappedSuperclass
#Inheritance(strategy= InheritanceType.SINGLE_TABLE)
public interface IState {}
public class BusState implements IState{}
//register subtype in mapper
mapper.registerSubtypes(BusState .class);
public interface Car {
public void setState(IState state);
}
#Entity
public class Bus implements Car {
private BusState state;
public void getState(BusState state) { //Seems fasterxml doesn't use this method, instead it use Car.setState
this.state = state;
}
}
I can create two different methods in Bus class: one for settingIState and one for BusState. But it looks ugly.
Question:
How can I make fasterxml to construct Bus-object correctly?
My entity class hierarchy is as follows.. ClassB which extends ClassA which extends abstract mappedsuperclass AbstractClass
AbstractClass
#MappedSuperclass
public abstract class AbstractClass implements Serializable
{
}
ClassA
#Table(name = "TABLE_ONE")
#SecondaryTable(name = "TABLE_TWO",
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="Type", discriminatorType=DiscriminatorType.STRING)
#DiscriminatorValue("ClassA")
public class ClassA extends AbstractClass
{
#Column(name = "CLASSA_XML")
private String ClassAXML;
#PrePersist
#PreUpdate
public void covertObjectToXml()
{
this.ClassAXML= JAXBUtilities.marshal(Object);
}
#PostLoad
public void convertXmlToObject()
{
//does unmarshal
}
}
ClassB
#DiscriminatorValue("ClassB")
public class ClassB extends ClassA
{
#Column(name = "CLASSB_XML", table = "TABLE_TWO")
private String ClassBXML;
#PrePersist
#PreUpdate
public void covertObjectToXml()
{
this.ClassAXML= JAXBUtilities.marshal(Object);
}
#PostLoad
public void convertXmlToObject()
{
//does unmarshal
}
}
Problem : when i persist using ClassB entity. ClassA callback methods are not called and value in my classAXml attribute is not persisted.
Is there anyway to generalize callback method(i.e covertObjectToXml and convertXmlToObject) for my inherited entity class structure.. so that when i persist using
both ClassA and ClassB individually, my callback methods are called respectively based on inheritance and their values can be persisted.
Note:
I have removed the callback methods from ClassA and generalize it in
classB and persist but my requirement is mainly individual
persistent of classA and ClassB.
my call back methods should not be in mapedSuperClass i.e AbstractClass.
Thanks in advance
There are two possibilities to reuse the callback code from ClassA in ClassB:
I. The best/most elegant way is to move the whole code to a new class, say MyEntityListeners
and then to use the #EntityListeners annotation on your entity classes like
#EntityListeners(class=MyEntityListeners.class)
public class ClassB extends ClassA {
.....
}
public class MyEntityListeners {
#PrePersist
public void onPrePersist(Object entity) {
//logic with entity (check the class of the entity or you can use `ClassA` instead of `Object`)
}
}
Please note that the EntityListeners are inherited in the subclasses from superclasses, so you do not need to do anything in ClassB if the EntiyListeners are already defined in ClassA (but you can add additional EntityListeners in ClassB, that are not in ClassA). For excluding all EntityListeners from the hierarchy you can use #ExcludeSuperclassListeners
II. If you have less callback methods and a small hierarchy tree, than you could overwrite and re-annotate every callback from ClassA also in ClassB like
...
public class ClassB extends ClassA {
......
#Override
#PrePersist
public void myCallback() {
super.myCallback();
}
......
}
This is what I'm trying to do:
#XmlRootElement(name = "bar")
#XmlAccessorType(XmlAccessType.NONE)
public abstract class Bar {
}
public final class Foo extends Bar {
#XmlElement
public String getMsg() {
return "hello, world!";
}
}
Now I'm trying to marshall an instance of class Foo:
com.sun.istack.SAXException2: unable to marshal type "Foo" as
an element because it is missing an #XmlRootElement annotation
What is a workaround?
Can you get away without the #XmlRootElement annotation on the superclass. Instead you should put it on each of your subclasses. JAX-B will still know about the superclass fields.