how to access JsonPropertyOrder - java

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

How to declare a variable or Object of any class type in Java

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

Jackson XmlMapper generates wrong XML entries order

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.

Jackson json only convert selected fields and methods

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

How to use Jackson Annotation to do a mapping for deserialization

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?

Use root name as property in entity

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

Categories

Resources