I have a POJO with JsonPropertyOrder defined, in other class I need to retrieve that order for that POJO, how can I do do this?
Example POJO:
#JsonPropertyOrder({"field1", "field2", "field3"})
public class ReportRow extends Row {
private String field1;
private String field2;
private String field3;
}
Can I try something like this: ReportRow.getJsonPropertyOrder()?
You're on the right track, you can get annotation information for the class and then access it's properties:
JsonPropertyOrder jpo = ReportRow.class.getAnnotation(JsonPropertyOrder.class);
String[] propertyOrder = jpo.value();
In this case you can find the taget attribute in the Jackson JsonPropertyOrder.java source.
Adding to the answer provided, you can get to the annotation through Jackson:
ObjectMapper mapper = new ObjectMapper();
JavaType type = mapper.getTypeFactory().constructType(ReportRow.class);
BeanDescription desc = mapper.getSerializationConfig().introspect(type);
JsonPropertyOrder jpo = desc.getClassAnnotations().get(JsonPropertyOrder.class);
Related
I am quite new to Java and I am trying to deserialize the JSON using Jackson and I facing some minor issue with regards to declaring the Object/Variable type. I will provide all the codes then explain the issue for easy understanding.
I have an enum that will have the required type values:
public enum IdentifierTypeValues {
Type1,
Type2,
Type3,
//Constructor and Getter of enum values
}
Then for each of these type, I have different classes which will have different input and do a completely different type of process:
public class GenerateType1 {
private String name;
private String age;
//Getter and Setter
//Some required process based on these values
}
public class GenerateType2 {
private String address;
private String city;
private String country;
//Getter and Setter
//Some required process based on these values
}
public class GenerateType3 {
private String firstName;
private String lastName;
private String fullName;
//Getter and Setter
//Some required process based on these values
}
Now I have a wrapper class for these type of classes which will take the type based on enum and typeInfo values. I want the typeInfo values to be any of the class based type something like this:
public class TypeSyntax {
private IdentifierTypeValues indeitiferType;
private GenerateType1 / GenerateType2 / GenerateType3 identifierTypeValues;
//Here the identifierTypeValues can have the values for anytype
//How to declare a variable of any of these class type?
}
This is the class that will be used by my JSON for deserializing. I know I can add a wrapper class of those 3 types and provide that wrapper class as a type class for this. Something like this:
public class WrapperClass{
private GenerateType1 type1;
private GenerateType2 type2;
private GenerateType3 type3;
}
public class TypeSyntax{
private IdentifierTypeValues indeitiferType;
private WrapperClass identifierTypeValues;
//But using this approach will change my JSON structure which I do not want to do.
}
My JSON structure is something like this and I would like to keep it in the same way.
{
"indeitiferType":"Type1",
"identifierTypeValues":{
"name":"Batman",
"age":"2008"
}
}
Is there a way I can declare the variable of multiple type class? or any better approach to handle this by keeping the json format same? I tried searching but I am unable to search what exactly so any help would be really appriciated.
Because the type identifier exists on a different level than the other properties a wrapper class TypeSyntax needed. There are several open feature requests to add wrapping functionality to Jackson e.g. https://github.com/FasterXML/jackson-databind/issues/512
Fortunately polymorphism is supported in Jackson with #JsonTypeInfo and #JsonSubTypes annotations.
Wrapper class should look like:
public class TypeSyntax {
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "identifierType")
private GenerateTypeBase identifierTypeValues;
// getters and setters (omitted for brevity)
}
GenerateTypeBase is the common parent class
#JsonSubTypes({
#JsonSubTypes.Type(value = GenerateType1.class, name = "Type1"),
#JsonSubTypes.Type(value = GenerateType2.class, name = "Type2"),
})
public abstract class GenerateTypeBase {
private String name;
private String age;
// getters and setters (omitted for brevity)
}
In this different children classes will instantiated based on the identifierType property.
The children must extend this base class:
public class GenerateType2 extends GenerateTypeBase {
// additional properties
}
In a short test it will be:
#Test
void wrapperTest() throws IOException {
ObjectMapper mapper = new ObjectMapper();
GenerateType2 a = new GenerateType2();
a.setName("Foo");
a.setAge("13");
TypeSyntax w = new TypeSyntax();
w.setIdentifierTypeValues(a);
String json = mapper.writeValueAsString(w);
System.out.println(json);
}
and the output:
{
"identifierTypeValues":
{
"name":"Foo",
"age":"13"
},
"identifierType":"Type2"
}
Deserialization
#Test
void wrapperTest() throws IOException {
ObjectMapper mapper = new ObjectMapper();
String input = "{\"identifierTypeValues\": \"name\":\"Foo\",\"age\":\"13\"},\"identifierType\":\"Type2\"}";
TypeSyntax w = mapper.readValue(new StringReader(input), TypeSyntax.class);
assertAll(
() -> assertEquals(GenerateType2.class, o.getIdentifierTypeValues().getClass()),
() -> assertEquals("13", o.getIdentifierTypeValues().getAge())
);
}
If you want more flexibility you can write custom (de)serializer and / or custom resolver. Using custom TypeIdResolver that will possible to convert identifiers to types programmatically instead of using "key-value pairs" in #JsonSubTypes
I have an issue with generating a XML string with the Java Jackson XmlMapper: It generates the wrong order of entries in the XML string, nevertheless I use #JsonPropertyOrder and the members are in the needed order inside the class.
Please see my code:
#JsonPropertyOrder({ "craneNumber", "moveType", "reference", "unitNumber", "ISOCode", "IMOLabels", "seal", "doorDirection" })
public class OcrDataResultUnit {
#JacksonXmlElementWrapper(localName="unit")
private String craneNumber;
private String moveType;
private String reference;
private String unitNumber;
#JsonProperty("ISOCode")
private String isoCode;
#JacksonXmlElementWrapper(localName="IMOLabels")
#JsonProperty("DGSIMOClass")
private List<String> imoLabels = new ArrayList<>();
#JsonProperty("seal")
private String seal;
#JsonProperty("doorDirection")
private String doorDirection;
// all getters and setters ...
Usage:
XmlMapper mapper = new XmlMapper();
String msgXml = mapper.writeValueAsString(this);
Result:
<unit>
<craneNumber>QC01</craneNumber>
<moveType>D</moveType>
<reference>12345678901234567890123456789012</reference>
<unitNumber>ABCD00001234</unitNumber>
<ISOCode>22G1</ISOCode>
<seal>Y</seal>
<doorDirection>H</doorDirection>
<IMOLabels>
<DGSIMOClass>1.5</DGSIMOClass>
<DGSIMOClass>2.1</DGSIMOClass>
</IMOLabels>
</unit>
I get the same result without the #JsonProperty on the last to members. That was a try.
The structure is part of a bigger XML structure.
Also replaced #JsonProperty with #JacksonXmlProperty: Same result.
As far as I see #JsonPropertyOrder is correct to be used for XML as well.
Does anybody have an idea?
Maybe I am just blind - actually I hope so :-)
Thank you and best regards
In your JsonPropertyOrder annotation, the property is called "DGSIMOClass", not "IMOLabels". You should switch it out for the correct name.
With jackson there is a way to ignore some fields using #JsonIgnore. Is there a way to do the opposite, and only show fields with are annotated? I'm working with an external class with a lot of fields and I only want to select a small subset of them. I'm getting tons of recursion problems (using some type of ORM) where object A -> B -> A -> B -> A .... which are not even necessary to export.
You can configure the object mapper to ignore absolutely everything unless specified by JsonProperty,
public class JacksonConfig {
public static ObjectMapper getObjectMapper(){
//The marshaller
ObjectMapper marshaller = new ObjectMapper();
//Make it ignore all fields unless we specify them
marshaller.setVisibility(
new VisibilityChecker.Std(
JsonAutoDetect.Visibility.NONE,
JsonAutoDetect.Visibility.NONE,
JsonAutoDetect.Visibility.NONE,
JsonAutoDetect.Visibility.NONE,
JsonAutoDetect.Visibility.NONE
)
);
//Allow empty objects
marshaller.configure( SerializationFeature.FAIL_ON_EMPTY_BEANS, false );
return marshaller;
}
}
public class MyObject {
private int id;
#JsonProperty
private String name;
private Date date;
//Getters Setters omitted
in this case only name would be serialized.
Sample repo, https://github.com/DarrenForsythe/jackson-ignore-everything
Yes definitely you can; Create a class with only the feilds you need and add the below property in the object mapper and rest is done.
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES to false
You can use #JsonIgnoreProperties(ignoreUnknown=true) on the pojo class so only the fields which are available in the pojo class will be mapped and resf will be left out.
For example
Json data
{
"name":"Abhishek",
"age":30,
"city":"Banglore",
"state":"Karnatak"
}
pojo class
#JsonIgnoreProperties(ignoreUnknown=true)
Class Person{
private int id;
private String name;
private String city;
}
Here state in not present in the Person class so that field won't be mapped
I'm using Jackson CSV to parse a CSV file into POJOs, like this.
List<SomeThing> something = csvMapper.readerFor(SomeThing.class).with(emptySchema().withHeader()).readValue(filecsv);
My issue is that I would like wrap my SomeThing list on a root Object, like this.
#JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use =
JsonTypeInfo.Id.NAME)
public class SomeThingWrapper extends BaseDto {
#JsonProperty("something")
private List<something> somethings;
}
So the previous code can be write like this :
SomeThingWrapper somethingWrapper = csvMapper.readerFor(somethingWrapper.class).with(emptySchema().withHeader()).readValue(filecsv);
My SomeThing POJO
#JsonRootName("SomeThing")
public class SomeThing {
#JsonProperty("ID")
private String id;
}
How would you suggest to be the best way to do this?
I'm kind of new in jackson subject and I did not find any answer which would help me resolve the problem.
For a sec let's assume that I have this class:
public class Airport {
private String name;
private String code;
...
}
My json looks like this:
"XXX": {
"name": "SomeName",
}
I would like to force Jackson to put XXX (root of tree) into code property from the class. Standard way I use to create objects from JSON is using treeToValue:
ObjectMapper mapper = new ObjectMapper();
String airports = "above Json";
JsonNode airportsTree = mapper.readTree(airports.toString());
Airport airport = mapper.treeToValue(airportsTree, Airport.class);
However when I enable DeserializationFeature.UNWRAP_ROOT_VALUE I'm getting
JsonMappingException: Root name 'XXX' does not match expected ('JsonNode') for type [simple type, class com.fasterxml.jackson.databind.JsonNode]
You need put root name hint for jackson
#JsonRootName(value = "XXX")
public class Airport {
private String name;
private String code;
...
}
When you enable DeserializationFeature.UNWRAP_ROOT_VALUE it must works