There is a POJO:
class A {
private B b;
}
where B:
class B {
private String c;
}
Is there a proper way of making Jackson serialize object of A, having A.b = null(or even b having all of it's fields as empty or default) in a form of:
{
b: {}
}
And without the use of custom serializers. The upper POJO is actually complex, and maintaining the serializer will bring more trouble than benefit.
Set default property inclusionto to Include.NON_NULL:
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.IOException;
public class JsonApp {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.setDefaultPropertyInclusion(Include.NON_NULL);
System.out.println(mapper.writeValueAsString(new A()));
}
}
class A {
private B b = new B();
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
class B {
private String c;
public String getC() {
return c;
}
public void setC(String c) {
this.c = c;
}
}
Above code prints:
{
"b" : { }
}
Related
I am using MapStruct 1.5.2.Final
Map struct is unable to map the target values using the parameterised constructor. Following is the parameterised constructor for the class.
I know that if I would have exposed the setters, this would have worked.
I don't want to expose the setters for my class as I want my class to be immutable.
#JsonCreator
public PassengerInfo(
#JsonProperty("a") final String a,
#JsonProperty("b") final String b) {
this.a = a;
this.b = b;
}
I am getting the following error
error: Property "a" has no write accessor in class.
error: Property "b" has no write accessor in class.
Also, this is the only constructor in my class.
Following is my class
public class Clazz {
private final String a;
private final String b;
#JsonCreator
public Clazz(
#JsonProperty("a") final String a,
#JsonProperty("b") final String b) {
this.a = a;
this.b = b;
}
public String getA() {
return a;
}
public String getB() {
return b;
}
}
Your code seems fine. There must be something else in your project.
#Getter
#Setter
public class PassengerEntity {
private String a;
private String b;
}
public class PassengerInfo {
private final String a;
private final String b;
#JsonCreator
public PassengerInfo(
#JsonProperty("a") final String a,
#JsonProperty("b") final String b) {
this.a = a;
this.b = b;
}
public String getA() {
return a;
}
public String getB() {
return b;
}
}
#Mapper
public interface PassengerMapper {
PassengerInfo mapPassenger(PassengerEntity entity);
}
class PassengerMapperTest {
private PassengerMapper passengerMapper;
#BeforeEach
void setUp() {
passengerMapper = Mappers.getMapper(PassengerMapper.class);
}
#Test
void testMapper() {
PassengerEntity entity = new PassengerEntity();
entity.setA("valueA");
entity.setB("valueB");
PassengerInfo info = passengerMapper.mapPassenger(entity);
Assertions.assertEquals("valueA", info.getA());
Assertions.assertEquals("valueB", info.getB());
}
}
=> test is OK
I have a json string which looks like:
{"a":5, "b":"asd", "c":"{\"d\":3}"}
This can be deserialized to an object like:
class A {
int a; // --> 5
String b; // --> 'asd'
String c; // --> '{"d":3}'
}
but i want it to be deserialized as:
class A {
int a; // --> 5
String b; // --> 'asd'
MyClass c; // --> '{"d":3}'
}
where MyClass is:
class MyClass {
int d; // --> 3
}
How can I achieve this in jackson during deserialization?
I just found out that I can use the jackson converter:
public class MyClassConverter implements Converter<String, MyClass> {
#Override
public MyClass convert(String value) {
try {
return new ObjectMapper().readValue(value, MyClass.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
#Override
public JavaType getInputType(TypeFactory typeFactory) {
return typeFactory.constructSimpleType(String.class, null);
}
#Override
public JavaType getOutputType(TypeFactory typeFactory) {
return typeFactory.constructSimpleType(MyClass.class, null);
}
}
And in the Bean:
class A {
int a;
String b;
#JsonDeserialize(converter = MyClassConverter.class)
MyClass c;
}
Try to do the deserialization twice:
A aObject = mapper.readValue(json,A.class);
aObject.setCObject(mapper.readValue(aObject.getC(),C.class));
class A {
int a;
String b;
String c;
C cObject;
}
class C {
int d;
}
Currently, I'm receiving this JSON input, which I have no control whatsoever:
{
"A" : {
"B" : {
"B" : [{
"Whatever" : "String",
"Number": 123
}
],
"SiblingObject" : true
}
}
}
Basically, I want to deserialize the B array that's inside the B object directly into the A class without having to create another extra class to wrap the B object. Something like this:
public class A {
private List<B> bList;
public List<B> getB() {
return bList;
}
#JsonProperty("B")
public void setB(List<B> bList) {
this.bList = bList;
}
}
I've tried doing
public class A {
private List<B> bList;
public List<B> getB() {
return bList;
}
#JsonProperty("B")
public void setB(Map<String, Object> bList) {
this.bList = (List<B>) bList.get("B");
}
}
but to no avail.
Any ideas?
There is one way of doing it. However, it will require traversing the input JSON twice.
In first pass, you create the normal A instance without the List.
In second pass, you use Jackson's node traversal to reach the correct B object and parse from there.
See the code below:
public class WrapperJsonTest {
public static void main(String[] args) {
ObjectMapper om = new ObjectMapper();
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("wrapper.json");
A a = null;
try {
a = om.readValue(in, A.class);
} catch (Exception e){
e.printStackTrace();
}
in = Thread.currentThread().getContextClassLoader().getResourceAsStream("wrapper.json");
try {
JsonNode node = om.readValue(in, JsonNode.class).get("B").get("B");
JsonParser parser = node.traverse();
List<B> bList = om.readValue(parser, List.class);
a.setB(bList);
System.out.println(a.isSibling());
System.out.println(a.getB());
} catch (Exception e){
e.printStackTrace();
}
}
#JsonIgnoreProperties
public static class A {
#JsonIgnore
private List<B> bList;
private boolean sibling;
public List<B> getB() {
return bList;
}
public void setB(List<B> bList) {
this.bList = bList;
}
public boolean isSibling() {
return sibling;
}
public void setSibling(boolean sibling) {
this.sibling = sibling;
}
}
public static class B {
private String whatever;
public String getWhatever() {
return whatever;
}
public void setWhatever(String whatever) {
this.whatever = whatever;
}
#Override
public String toString() {
return whatever;
}
}
}
I'm trying to serialize a simple hierarchy:
public class RootClass {
#Element
private final int a;
public RootClass( int a) {
this.a = a;
}
}
class SubClass extends RootClass {
#Element(name="b")
int b;
public SubClass() {
super(0);
this.b=0;
}
}
when I run
SubClass sub = new SubClass();
Serializer serializer = new Persister();
StringBuilderWriter writer = new StringBuilderWriter(1000);
serializer.write(sub, writer);
I get:
ConstructorException: Default constructor can not accept read only
#org.simpleframework.xml.Element(name=, data=false, type=void, required=true)
on field 'a' private final int
com.informatica.b2b.structurediscovery.serialization.tests.RootClass.a in class
com.informatica.b2b.structurediscovery.serialization.tests.SubClass
I couldn't find any way to make it work.
What is Serializer? if you want to serialize your object, you should implement the interface Serializable. Here is my code:
public class RootClass implements Serializable{
private final int a;
public RootClass(int a) {
this.a = a;
}
public void print(){
System.out.println(a);
};
}
public class SubClass extends RootClass {
int b;
public SubClass() {
super(0);
this.b = 0;
}
public void print() {
super.print();
}
}
SubClass sub = new SubClass();
sub.print();
try {
File file = new File("SubClass");
if (!file.exists())
file.createNewFile();
FileOutputStream fileOut = new FileOutputStream(file);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(sub);
out.close();
fileOut.close();
} catch (IOException i) {
i.printStackTrace();
}
You need to pass in the value for a like so.
class SubClass extends RootClass {
#Element(name="b")
int b;
public SubClass(#Element(name="a")int a) {
super(a);
this.b=0;
}
}
Or try this
class SubClassSubstitute {
#Element
int a;
#Element
int b
public SubClassSubstitute(#Element(name="a")int a, #Element(name="b")int b){
this.a = a;
this.b = b;
}
#Resolve
public SubClass resolve() {
return new Subclass(a)
}
}
class SubClass extends RootClass {
#Element(name="b")
int b;
public SubClass(#Element(name="a")int a) {
super(a);
this.b=0;
}
public SubClassDelegate replace() {
return new SubClassSubstitute(a, b);
}
}
The above works the same as readResolve() and writeReplace() in java object
I think this question has been asked like a million times, but none of solutions suggested worked for me. Here is my sample implementation
public class FooImpl2 implements Foo {
private int a = 100 ;
private String b = "I am FooImpl2";
private boolean c;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public boolean isC() {
return c;
}
public void setC(boolean c) {
this.c = c;
}
}
#XmlRootElement
#XmlSeeAlso({FooImpl1.class, FooImpl2.class})
public interface Foo {}
public class FooImpl1 implements Foo {
private int x;
private String y ="I am FooImpl1";
private boolean z;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public String getY() {
return y;
}
public void setY(String y) {
this.y = y;
}
public boolean isZ() {
return z;
}
public void setZ(boolean z) {
this.z = z;
}
}
#XmlRootElement
public class Response{
private Foo foo;
#XmlElement(type=Object.class)
public Foo getFoo() {
return foo;
}
public void setFoo(Foo foo) {
this.foo = foo;
}
}
public class SimpleResource {
#Path("foo/{val}") #Produces({"application/json"}) #GET
public FooAdapter getFoo(#QueryParam("val") int val) {
FooAdapter ret = new FooAdapter();
if(val % 2 == 0) {
ret.setFoo(new FooImpl2());
} else {
ret.setFoo(new FooImpl1());
}
return ret;
}
I always get following exception
com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of
IllegalAnnotationExceptions
com.abc.objectsToReturn.Foo is an
interface,
can any one help me to figure out right solution
This isn't really an interface issue, you just need to change the way you bootstrap your JAXBContext.
If you change it to the following:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Response.class, FooImpl1.class, FooImpl2.class);
Response response = new Response();
FooImpl1 foo = new FooImpl1();
response.setFoo(foo);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(response, System.out);
}
}
Then you will get the following output (with any JAXB implementation: Metro, MOXy, etc):
<response>
<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="fooImpl1">
<x>0</x>
<y>I am FooImpl1</y>
<z>false</z>
</foo>
</response>
MOXy JAXB allows your entire model to be interfaces, checkout:
http://bdoughan.blogspot.com/2010/07/moxy-jaxb-map-interfaces-to-xml.html
I also have a blog post that may be relevant to what you are trying to build:
http://bdoughan.blogspot.com/2010/08/using-xmlanyelement-to-build-generic.html
When you use interfaces just to hide your implementation classes from exposure, and when there's 1-to-1 (or close to 1-on-1) relationship between a class and an interface, XmlJavaTypeAdapter can be used like below.
#XmlJavaTypeAdapter(FooImpl.Adapter.class)
interface IFoo {
...
}
class FooImpl implements IFoo {
#XmlAttribute
private String name;
#XmlElement
private int x;
...
static class Adapter extends XmlAdapter<FooImpl,IFoo> {
IFoo unmarshal(FooImpl v) { return v; }
FooImpl marshal(IFoo v) { return (FooImpl)v; }
}
}
class Somewhere {
public IFoo lhs;
public IFoo rhs;
}