How to ignore JSON properties similar to #JsonIgnore in Deserialization - java

I have a JSON object similar below:
[
{
"objA": {
"propA": "AAAA",
"propB": "BBBB",
"objB": {
"objC": {
"propC": "CCCC",
"propD": "DDDD"
}
},
"objD": [
"asa"
],
"propE": "AW",
"propF": "533",
"propG": "ABW",
"propH": "ARU",
"objE": {
"objF": {
"propI": "SASDS",
"propJ": "54DEFF"
}
}
}
}
]
When I deserialize this JSON into a List, I would like to do for part of this object, for example: I would like to ignore objB, objC, objD, objE and objF.
To do that I has been used the #JsonIgnore annotation. So I did something like that:
public class MyClass {
// objects and properties not ignorabled
private ClassA objA;
private String propE;
private String propF;
private String propG;;
private String propH;
// objects ignorabled in deserialization
#JsonProperty("objB")
#JsonIgnore
private Object objB;
#JsonProperty("objD")
#JsonIgnore
private Object objD;
#JsonProperty("objE")
#JsonIgnore
private Object objE;
/** gets and setters here **/
Follow below the piece of code that deserialize my JSON
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(url, new TypeReference<List<MyClass>>(){});
This code is working. this code is ignoring the objects from JSON, but I believe there are some another way to do that instead of use #JsonIgnore to each object or property in my entity.
Do you know how can I do that better?

Do you want to avoid using # notations ?
If not, have you tried using a filter like #JsonFilter("myFilter") in Jackson ? As described here: https://www.baeldung.com/jackson-ignore-properties-on-serialization
See also https://www.tutorialspoint.com/jackson_annotations/jackson_annotations_jsonfilter.htm
So you would have to write:
#JsonFilter("myFilter")
public class MyClass { ... }
in your class. Then do something like:
SimpleBeanPropertyFilter objBFilter = SimpleBeanPropertyFilter
.serializeAllExcept("objB");
SimpleBeanPropertyFilter objDFilter = SimpleBeanPropertyFilter
.serializeAllExcept("objD");
SimpleBeanPropertyFilter objEFilter = SimpleBeanPropertyFilter
.serializeAllExcept("objE");
FilterProvider filters = new SimpleFilterProvider()
.addFilter("objBFilter", theFilter)
.addFilter("objDFilter", theFilter)
.addFilter("objEFilter", theFilter);

Related

How would I print an object's name as part of the JSON in Java's Jackson library?

I'm trying to determine how to print out a JSON that looks like this, using Java's Jackson library:
{
"status": {
{
"busStatus" : {
"status" : null,
"transactions" : "0",
"retries" : "0",
"failures" : "0"
}
}
}
}
I'm 95% there, but the outermost object is not currently being printed. This is what I'm currently getting outputted:
{
"busStatus" : {
"status" : null,
"transactions" : "0",
"retries" : "0",
"failures" : "0"
}
}
I have a Java class that looks like this:
public class DataClass {
public StatusData status = new StatusData();
public StatusConfig config = new StatusConfig();
public class StatusData {
public SerialStatus busStatus = new SerialStatus();
}
public class StatusConfig {
}
public class SerialStatus {
public String status = null;
public String transactions = "0";
public String retries = "0";
public String failures = "0";
}
}
I'm printing this class to json using the code below:
private DataClass internalData;
ObjectMapper mapper = new ObjectMapper();
status = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(internalData.status);
Is there a way I can configure Jackson to print out the name of the object its serializing into the JSON?
To achieve what you want, you need to print DataClass instead of StatusData. Something like below:
private DataClass internalData = <initialize>;
ObjectMapper mapper = new ObjectMapper();
String data =
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(internalData);
You can use Jackson Filter to control the serialization process, I think it should work with your use case, at least one way to do it.
Use the filter annotation and then create two different filters for your class, where you can define which field to skip, and use it with the ObjectMapper accordingly to convert the whole internalData object, so when you need to skip the status, use one filter and when you need to skip the config associate the other filter with the mapper, while always serializing the parent object. Which should give you the structure you want.
#JsonFilter("filter_serializer")
class User {
public String v1;
public String v2;
}
String[] fieldsToSkip = new String[] { "v1" };
ObjectMapper mapper = new ObjectMapper();
final SimpleFilterProvider filter = new SimpleFilterProvider();
filter.addFilter("filter_serializer",
SimpleBeanPropertyFilter.serializeAllExcept(fieldsToSkip));
User dtoObject = new User();
dtoObject.v1 = "v1";
dtoObject.v2 = "v2";
String jsonStr = mapper.writer(filter).writeValueAsString(dtoObject);
I was able to find the solution I was looking for, from this website.
I've gotten rid of the DataClass and now only have a StatusData and a StatusConfig class. I've included how the StatusData class would look below:
#JsonRootName(value = "status")
public class StatusData {
String status;
String transactions;
// so on
}
To parse the class, I needed to add the JsonRootName annotation above, and also enable a feature on the mapper, as below:
private DataClass internalData;
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE); // don't forget this!
statusText = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(statusObject);
Separately, if you'd like to deserialize a JSON like the one I had into a class like StatusData, do this:
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
statusObject = mapper.readValue(statusText, StatusData.class);

Jackson: Deserialize JSON array from JSON object into Java List

I have been stumbled by this for a while. I have a Spring application and would like to parse the following JSON:
{
"metadata": {...}
"response": {
"objects": [
{
"name": "someName",
"properties": [<array_of_properties>]
},
...
]
}
}
into a list of the following Java objects:
public class MyClass {
String name;
List<CustomProperties> customProperties;
}
Meaning, I want to extract only the objects array and parse only that. I have tried using a custom deserializer and that works, but I had to do:
#JsonDeserialize(using=MyDeserializer.class)
public class MyClassList extends ArrayList<MyClass>{}
and then:
ObjectMapper objectMapper = new ObjectMapper();
List<MyClass> list = objectMapper.readValue(json, MyClassList.class)
Is there anyway to avoid extending ArrayList, since currently I am doing that in order to be able to access the .class property.
you can define your json structure with a couple of classes
public class MyJson {
private MyResponse response;
...
}
public class MyResponse {
private List<MyClass> objects;
...
}
public class MyClass {
String name;
List<CustomProperty> customProperties;
...
}
than you can use Jackson to parse the json string to MyJson class, no special #JsonDeserialize is needed
ObjectMapper objectMapper = new ObjectMapper();
MyJson myJson = objectMapper.readValue(json, MyJson.class);
List<MyClass> list = myJson.getResponse().getObjects();
Keep in mind, this code is only a draft, all classes should have setters (and getters) and some null checks are required
You can do something like this. I feel this would be cleaner
#JsonIgnoreProperties(ignoreUnknown = true)
class Wrapper{
private Response response;
//setters, getters
}
#JsonIgnoreProperties(ignoreUnknown = true)
class Response{
private List<MyClass> objects;
//setters, getters
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyClass {
String name;
List<CustomProperties> customProperties;
//setters, getters
}
ObjectMapper objectMapper = new ObjectMapper();
Wrapper wrapper = objectMapper.readValue(json, Wrapper.class)
You can extrat objects and consequently CustomProperties by traversing the list. You can declare only fields which you are interested in and ignore others by #JsonIgnoreProperties(ignoreUnknown = true)(for example i have not included metadata)

Java - Object Mapper - JSON Array of Number to List<Long>

In my front end I send this JSON:
"ids": [ 123421, 15643, 51243],
"user": {
"name": "John",
"email": "john#sovfw.com.br"
}
To my Spring Endpoint below:
#PostMapping(value = "/sendToOficial")
public ResponseEntity<?> sendToOficial(#RequestBody Map<String, Object> payload) {
ObjectMapper mapper = new ObjectMapper();
List<Long> pointsIds = mapper.convertValue( payload.get("pointsIds"), List.class );
UsuarioDTO autorAlteracao = mapper.convertValue(payload.get("user"), UsuarioDTO.class);
for (Long idPoint : pointsIds) { ... }
But I'm getting a Cast Exception in the for saying that it can't cast Integer to Long.
I can't receive the "ids" numbers as Integer, I want to receive as Long.
Please, how could I do this?
First, define POJOs for mapping your request object:
public class RequestObj implements Serializable{
private List<Long> ids;
private UsuarioDTO user;
/* getters and setters here */
}
public class UsuarioDTO implements Serializable{
private String name;
private String email;
/* getters and setters here */
}
And then modify your endpoint:
#PostMapping(value = "/sendToOficial")
public ResponseEntity<?> sendToOficial(#RequestBody RequestObj payload) {
In this way you also do not need to use an ObjectMapper. Just call payload.getIds().
Consider also that in this way if payload changes you'll need only to change RequestObj definition, while using ObjectMapper would force you to update also your endpoint in an important way. It's better and safer to separate payload representation from control logic.
In jackson-databind-2.6.x and onward versions you can configure the ObjectMapper to serialize low typed int values (values that fit in 32 bits) as long values using the DeserializationFeature#USE_LONG_FOR_INTS configuration feature:
#PostMapping(value = "/sendToOficial")
public ResponseEntity<?> sendToOficial(#RequestBody Map<String, Object> payload) {
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature .USE_LONG_FOR_INTS, true);
List<Long> pointsIds = mapper.convertValue( payload.get("pointsIds"), List.class );
UsuarioDTO autorAlteracao = mapper.convertValue(payload.get("user"), UsuarioDTO.class);
for (Long idPoint : pointsIds) { // ... }
}
If you just want your mapper to read into a List<Long>, use this trick for obtaining full generics type information by sub-classing.
Example
ObjectMapper mapper = new ObjectMapper();
List<Long>listOfLong=mapper.readValue("[ 123421, 15643, 51243]" ,
new TypeReference<List<Long>>() {
});
System.out.println(listOfLong);
Prints
[123421, 15643, 51243]

How to unmarshall json lists using Spring Boot RestTemplate

I have to parse a REST response in json and it has a lot of nested lists with many objects.
The response contains an item called "ObjectList" which has a list and inside, two elements, "ObjectA" and "ObjectB". I don't know how to parse the response to objects using Jackson annotations.
The json looks like this:
"ObjectList": [
{
"ObjectA": {
"property1": false,
"property2": true
},
"ObjectB": {
"property1": 66,
"property2": true
},
{
"ObjectA": {
"property1": false,
"property2": true
},
"ObjectB": {
"property1": 66,
"property2": true
}
}
]
}
My code looks like this
ResponseEntity<Response> response = restTemplate.exchange(URL, HttpMethod.GET, request, Response.class);
Response response = response.getBody();
Response is:
#JsonIgnoreProperties(ignoreUnknown = true)
public class TimesheetListResponse {
#JsonProperty("ObjectA")
private List<ObjectA> objectAList;
#JsonProperty("ObjectB")
private List<ObjectB> objectBList;
That does not work at all, and I'm confused about how to map this.
According to your requirement the model structure may look like below. Within the objectList map in Response object, you need to add HashMap with keys as "ObjectA"/"ObjectB" string and value as instance of ObjectA/ObjectB. I have taken value type of Map as Object, so that any object type A/B can fit in there. Add corresponding #JsonXXX annotations.
public class Response {
private List<Map<String,Object>> objectList;
//Getters & Setters
}
public class ObjectB {
String propB1;
String propB2;
}
public class ObjectA {
String propA;
String propA1;
}
I also would consider the entry in the list as another wrapper object that can either ObjectA or ObjectB. I.e.
#JsonIgnoreProperties(ignoreUnknown = true)
public final class Parent {
#JsonProperty("ObjectList")
private List<ChildWrapper> objectList = new ArrayList<>();
}
#JsonIgnoreProperties(ignoreUnknown = true)
public final class ChildWrapper {
#JsonProperty("ObjectA")
private Child ObjectA;
#JsonProperty("ObjectB")
private Child ObjectB;
}
#JsonIgnoreProperties(ignoreUnknown = true)
public final class Child {
#JsonProperty("property1")
private int property1;
#JsonProperty("property2")
private boolean property2;
}
It seems that the mapping was fine, I only had to initialize the Arraylist. The main issue was that the endpoint was returning empty because of a parameter that I forgot.

How can I get a reader method based on a json property name using jackson?

Given the following jackson annotated class :
public class AClass {
#JsonProperty("propertyName")
private String anyProperty
public String getAnyProperty() {
...
}
...
}
or a mixin configuration:
public class AClass {
private String anyProperty
public String getAnyProperty() {
...
}
...
}
public interface AClassMixin {
#JsonProperty(value = "propertyName")
String getAnyProperty();
}
How can I get the json property "propertyName' reader method using jackson?
I need something like that:
ObjectMapper mapper = new ObjectMapper();
Method method = mapper.getReaderMethodForProperty("propertyName", Aclass.class);
Construct a JavaType for your bean class
JavaType target = objectMapper.constructType(AClass.class);
then use the ObjectMapper's DeserializationConfig to introspect it. This will give you a BeanDescription.
BeanDescription beanDescription = objectMapper.getDeserializationConfig().introspect(target)
You can use that to get a list of its BeanPropertyDefinition instances.
List<BeanPropertyDefinition> beanPropertyDefinitions = beanDescription.findProperties();
Each BeanPropertyDefinition has methods to retrieve getters and setters (and other things) as AnnotatedMember values from which you can retrieve the Member (you'll need to cast to Method).
for (BeanPropertyDefinition bpd : beanPropertyDefinitions) {
AnnotatedMember annotatedMember = bpd.getAccessor();
Member member = annotatedMember.getMember();
if (member instanceof Method) {
Method getterMethod = (Method) member;
System.out.println(getterMethod.getName());
}
}

Categories

Resources