I am new to Spring Boot and I am trying to figure out how to parse json data. I see a lot of tutorials on how to map json string object to an annotated Java class and using and object mapper, like this:
json:
{
"UUID": "xyz",
"name": "some name"
}
public class MyClass{
#JsonProperty
private UUID id;
#JsonProperty
private String name;
#JsonAnyGetter
public UUID getId() {
return this.id;
}
#JsonAnySetter
public void setId(UUID id) {
this.id = id;
}
#JsonAnyGetter
public String getName() {
return this.name;
}
#JsonAnySetter
public void setName(String name) {
this.name = name;
}
}
ObjectMapper objectMapper = new ObjectMapper();
MyClass customer = objectMapper.readValue(jsonString, MyClass.class);
The problem is that the system I am getting the json string from does not match the class naming conventions we use (and I cannot change either one). So, instead of having the example json string above, it might look like this:
{
"randomdstring-fieldId": "xyz",
"anotherrandomstring-name": "some name"
}
This use case only has two fields, but my use case has a larger payload. Is there a way to either map the field names from the json object to the field names in the Java class or is there a way to just parse the json string as a key value pair (so that I can just manually add the fields to my Java object)?
In Jackson with #JsonProperty you can customize the field name with it's annotation parameter value
Therefore, you just have to annotate the entity fields with the #JsonProperty annotation and provide a custom JSON property name, like this:
public class MyClass{
#JsonProperty("original_field_name_in_json")
private UUID id;
...
The #JsonProperty will do it for you:
#JsonProperty("name_in_json")
private Long value;
Related
I'm trying to convert an enum value into a custom string as part of a JSON response in a Java Spring application. I've attempted to override the enum's toString method and create a Spring converter but both attempts don't seem to work.
Sample Controller
#RequestMapping(value = "/test/endpoint", produces = APPLICATION_JSON_VALUE)
#RestController
public class RecommenderController {
...
#GetMapping("test")
public List<MyEnum> test() {
return new ArrayList<>() {{
this.add(MyEnum.SAMPLE);
}};
}
}
Enum
public enum MyEnum {
SAMPLE("sample"), OTHER_SAMPLE("other sample");
private final String name;
public MyEnum(String name) {
this.name = name;
}
public String toString() {
return this.name;
}
}
This code returns the response ["SAMPLE"] although I want it to return ["sample"]. Is there a way to implement this in Spring?
Assuming you are using the default MappingJackson2HttpMessageConverter, then behind the scenes you are using Jackson's ObjectMapper to perform all the JSON serialization and deserialization. So it's a matter of configuring Jackson for your protocol objects.
In this case, it's probably most straightforward tell Jackson that it can make a single JSON value for your instance of MyEnum with the #JsonValue annotation.
public enum MyEnum {
SAMPLE("sample"), OTHER_SAMPLE("other sample");
private final String name;
public MyEnum(String name) {
this.name = name;
}
#JsonValue
public String getValue() {
return this.name;
}
}
#JsonValue has a bonus, as described in its Javadoc:
NOTE: when use for Java enums, one additional feature is that value returned by annotated method is also considered to be the value to deserialize from, not just JSON String to serialize as. This is possible since set of Enum values is constant and it is possible to define mapping, but can not be done in general for POJO types; as such, this is not used for POJO deserialization.
So if you have the same Enum definition in your application that receives the list, it will deserialize the human readable value back into your Enum.
This can be done by using the #JsonValue annotation in the enum definition:
public enum MyEnum {
...
#JsonValue
public String getName() {
return this.name;
}
}
Let's say I have following flat JSON structure:
{
"name": "name",
"validFrom": "2018-01-09",
"validTo": "2018-01-10",
}
and MyPojo class:
public class MyPojo {
private String name;
#JsonUnwrapped
private Validity validity;
}
and Validity class:
public class Validity {
private LocalDate validFrom;
private LocalDate validTo;
}
I created custom unwrapping serializer and it works fine.
I would like to deserialize JSON above into MyPojo class which includes Validity value object.
How should custom deserializer for Validity be implemented?
#JsonProperty does not work as I want to use 2 Json properties for Validity construction
I would recommend a constructor in this case, a lot simpler than a custom deserializer, something like:
#JsonCreator
public MyPojo(#JsonProperty("name") String name,
#JsonProperty("validFrom") String validFrom,
#JsonProperty("validTo") String validTo) {
this.name = name;
this.validity = new Validity(validFrom, validTo);
}
It's implied that LocalDate is parsed from String above but you may have Jackson parse them.
You may skip annotations above if you use Java 8 with parameter names module
That will require an extra annotation on validity, see open Jackson issue here
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
#JsonUnwrapped
private Validity validity;
I'm mapping a Java object to JSON using Jackson, the object is a pretty simple pojo class that looks like this:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonProperty;
#JsonAutoDetect
public class Area {
#JsonProperty("Id")
public int Id;
#JsonProperty("Name")
public String Name;
public Area() {
Name = "";
}
public int getId() {
return Id;
}
public void setId(int id) {
Id = id;
}
public String getName() {
return Name;
}
public void setName(String Name) {
this.Name = Name;
}
}
The mapping code then looks like this:
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibilityChecker(mapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
areaJSON = mapper.writeValueAsString(area);
But the value of areaJSON at this point is then as follows:
{"id":0,"name":"","Name":"","Id":0}
Note the multiple values with differing case.
What am I doing wrong?
Jackson thinks that the fields Id and Name are different properties from the ones returned by the getters because the case is different. Using standard JavaBeans naming conventions, Jackson infers the fields corresponding to the getters are named id and name, not Id and Name.
tl;dr case matters.
There are two simple ways to fix this problem:
Remove the #JsonAutoDetect annotation from this class entirely. I'm pretty sure that the default annotation values are taking precedence over the ObjectMapper's configuration. Alternately:
Don't muck with the ObjectMapper at all. Change the #JsonAutoDetect on the class to
#JsonAutoDetect(
fieldVisibility = Visibility.ANY,
getterVisibility = Visibility.NONE,
setterVisibility = Visibility.NONE,
creatorVisibility = Visibility.NONE
)
You need to annotate getId method with #JsonProperty("Id"), otherwise getId will also be added with lowercase id.
I know that it's an old post, but there is a simpler solution:
use only annotation on fields:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Area {
public int id;
public String name;
public Area() {
name = "";
}
public int getId() {
return id;
}
public void setId(int id) {
id = id;
}
public String getName() {
return name;
}
public void setName(String Name) {
this.name = Name;
}
}
You can choose how to serialize the object: using the field or using the properties. If you use the fields, the getter and setter are ignored.
The problem in the code is created by the first letter uppercase : accessing the field, the json property is Id; accessing the getter , getId became id (first letter after get is coded in lower case).
The solution for me was to move annotations to either setters or getters (either one is fine)
I've a POJO and I want to create an instance of this class from JSON. I'm using jackson for converting JSON to Object. I want to ensure that JSON will conain all properties of my POJO. The JSON may contain other extra fields but it must contain all the attributes of the POJO.
Example:
class MyClass {
private String name;
private int age;
public String getName(){return this.name;}
public void setName(String name){this.name = name;}
public int getAge(){return this.age;}
public void setAge(int age){this.age = age;}
}
JSON #1
{
"name":"Nayan",
"age": 27,
"country":"Bangladesh"
}
JSON #2
{
"name":"Nayan",
"country":"Bangladesh"
}
Here, I want JSON#1 to be successfully converted to MyClass but JSON#2 should fail. How can I do this? Is there an annotation for this?
Well, there is an annotation that you could apply to your properties that say they are required.
#JsonProperty(required = true)
public String getName(){ return this.name; }
The bad part is, as of right now (2.5.0), validation on deserialization isn't supported.
...
Note that as of 2.0, this property is NOT used by BeanDeserializer: support is expected to be added for a later minor version.
There is an open issue from 2013 to add validation: Add support for basic "is-required" checks on deserialization using #JsonProperty(required=true)
I'm trying to use Gson to map JSON to POJO where the POJO contains a custom field that is not part of JSON. The field gets updated when the setters of other fields are invoked to add the names of the fields that are being updated to a list.
The POJO class looks something like this:
public class myPojo {
private List<String> dirtyFields;
private String id;
private String subject;
private String title;
public myPojo() {
dirtyFields = new ArrayList<String>();
}
public getId() {
return id;
}
public setId(String id) {
this.id = id;
}
public getSubject() {
return subject;
}
public setSubject(String subject) {
this.subject = subject;
dirtyFields.add("subject");
}
// more setter/getters
}
The dirtyFields ivar is not a deserialized field but it is used to keep track of the fields that are being updated.
After mapping, however, the list seems to become an empty list. This was not the case with Jackson.
Is this due to the expected Gson behaviour?
Gson does not call setter/getters during deserialization/serialization. It access, instead, directly to fields (even if private/protected) using reflection. This explains why your dirtyFields ivar is empty.
The possibility of calling setter/getters is not implemented in Gson as far as I know. The reason why Gson acts like this is explained better here. A comparison between Jackson and Gson features can be found here, you may be interested in setter/getter part.
However Gson is quite flexible to add a custom behavior to get what you need, you should start reading Read and write Json properties using methods (ie. getters & setters) bug
Another way to calculate your dirtyFields list could be using reflection and checking if every field of your POJO is null or not. You could start from this.