Jackson Converting String to Object - java

Link.java
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({ "rel", "href","method" })
public class Link {
#JsonProperty("rel")
private String rel;
#JsonProperty("href")
private String href;
#JsonProperty("method")
private Method method;
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}
I have this third party class with fasterxml jackson annotations. I can convert a given object into a string using the specified toString() method. Is there any way of using that String to get an object of type Link?
Note: The object itself has an embedded object (which has several more embedded objects) and these too needs to be converted into a Method object from the string itself.

Just putting the comment by #pvpkiran in an answer.
Use ObjectMapper class from com.fasterxml.jackson.databind
ObjectMapper objectMapper = new ObjectMapper();
Converting from Object to String:
String jsonString = objectMapper.writeValueAsString(link);
Converting from String to Object:
Link link = objectMapper.readValue(jsonString, type)

Related

Jackson MismatchedInputException (no String-argument constructor/factory method to deserialize from String value)

I am using SpringBoot 2.3.1-RELEASE and am trying to deserialize JSON string to a POJO containing list of objects but I keep running into this error:
Cannot construct instance of com.response.dto.RootDTO (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('Meta')
at [Source: (String)""Meta":[{"DimensionName":"Version","DimensionId":"3b4860b9-b215-4192-bd7a-a76f377fc465","DimensionType":"Regular","Alias":"C0","AttributeId":"211d5-d91f-40ec-9668-20e0da2ae7b3","AttributeName":"Version Name","AttributeKey":"VersionKey"; line: 1, column: 1]
This is what my JSON string looks like (but with escape chars in eclipse):
{"Meta":[{"DimensionName":"Version", "DimensionId":"3b4860b9-b215-4192-bd7a-a76f377fc465, "DimensionType":"Regular","Alias":"C0","AttributeId":"211b33d5-d91f-40ec-9668-20e0da2ae7b3","AttributeName":"Version Name","AttributeKey":"VersionKey"}]}.
Here is the class I want to deserialize it to:
#JsonIgnoreProperties(ignoreUnknown = true)
#Data
public class RootDTO
{
#JsonProperty("Meta")
private List<MetaDTO> Meta;
}
#JsonIgnoreProperties(ignoreUnknown = true)
#Data
public class MetaDTO
{
#JsonProperty("DimensionName")
private String DimensionName;
#JsonProperty("AttributeId")
private String AttributeId;
#JsonProperty("AttributeName")
private String AttributeName;
#JsonProperty("Name")
private String Name;
#JsonProperty("Alias")
private String Alias;
}
This is the code that blows up when trying to read the value:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.readValue(jsonFormattedString, RootDTO.class));
I only see this issue while running Junit (version : 4.12). I see jackson-databind-2.11.0, spring-test-5.2.7.RELEASE in the stack trace. However, I debug using a call from browser or postman it works fine. I am not sure why it is looking for the string Meta when I have specified it to be a list. What could be causing this issue? Any suggestions?
Edit: Turns out that the string which was being supplied to the ObjectMapper isn't the correct one. There is this line of code
String jsonFormattedString = responseEntity.getBody().substring(1, responseEntity.getBody().lastIndexOf("\"")).replaceAll("\\\\", ""); which makes my mocked string invalid. I'll need to figure out why we are doing this though.
Change the first letter's of variable to lowwer case. And remove the JsonProperty.
As below. And auto generate the setter and getter.
private String DimensionName;
private String attributeId;
private String attributeName;
private String name;
public void setName(String name){
this.name=name;
}
.........
.........
//All setter getter
Add #JsonGetter("Meta") each getter method.
For example as below.
#JsonGetter("Meta")
public List<Meta> getMeta(){
return meta;
}

How to parse JSON element that can be either simple string or an object into Class Object

I am not able to unmarshall a JSON key which can hold either a string value or an another JSON Object using Jackson Library.
Ex:- Below are the two possible values.
1)
"ProviderData": {
"INVALID": "HEX",
"#text": "Sample"
}
2)
"ProviderData": "1C"
Could someone please verify and suggest me on this issue.
You can write custom deserialiser and handle these both cases or write two constructors for ProviderData POJO class and properly use JsonCreator and JsonCreator annotations. See below example:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue(jsonFile, Response.class));
}
}
class Response {
#JsonProperty("ProviderData")
private ProviderData data;
// getters, setters, toString
}
class ProviderData {
private static final String INVALID_NAME = "INVALID";
private static final String TEXT_NAME = "#text";
#JsonProperty(INVALID_NAME)
private final String invalid;
#JsonProperty(TEXT_NAME)
private final String text;
#JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public ProviderData(String invalid) {
this(invalid, null);
}
#JsonCreator
public ProviderData(#JsonProperty(INVALID_NAME) String invalid, #JsonProperty(TEXT_NAME) String text) {
this.invalid = invalid;
this.text = text;
}
// getters, toString
}
For this JSON payload:
{
"ProviderData": {
"INVALID": "HEX",
"#text": "Sample"
}
}
Above example prints:
Response{data=ProviderData{invalid='HEX', text='Sample'}}
And for String primitive JSON payload:
{
"ProviderData": "1C"
}
Above example prints:
Response{data=ProviderData{invalid='1C', text='null'}}
As you can see, JSON Object is mapped properly using 2-arg constructor and String primitive is mapped using 1-arg constructor and we assume that this value means invalid key from JSON Object example.
See also:
Custom JSON Deserialization with Jackson.
sequentially deserialize using Jackson.
Deserialize strings and objects using jackson annotations in java.
you could deserialize to JsonNode and then extract the contents individually, or deserialize to an Object and use instanceof to determine if it's a Map or another type, or use a custom deserializer to unpack the data into a custom object that handles both cases.

Convert multiple Java Beans to JSON

I have multiple Java bean classes that are associated to each other (JSON Array + JSON Object) since they have a nested structure.
There are about 10 classes. Is there a way to collectively convert these classes or at-least one by one?
I had created these classes out of a JSON data which I don't have access to right now.
So, now, what I'm looking forward is to create a dummy JSON out of those classes.
Using GSON, I tried converting one of these Bean classes however, I got an empty result. Here is one of the beans called Attachment.java.
Attachment.java
package mypackagename;
import java.io.Serializable;
public class Attachment implements Serializable{
private Payload payload;
private String type;
public Payload getPayload() {
return payload;
}
public void setPayload(Payload payload) {
this.payload = payload;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
Implementation
Gson gson = new Gson();
Attachment attachment = new Attachment();
String json = gson.toJson(attachment);
Sure you got an empty result. Because your JSON object is empty. You should add data to your object and test it again as below:
Attachment attachment = new Attachment(new Payload("Test Payload"), "Test attachment");
String json = new Gson().toJson(attachment);
Log.e("Test", "Json: " + json); // result: Json: {"payload":{"test":"Test Payload"},"type":"Test attachment"}
To avoid empty object, you have to set a default value to your payload and type becaus Gson will ignore any null value.
This section of the Gson User Guide: https://sites.google.com/site/gson/gson-user-guide#TOC-Finer-Points-with-Objects
The fourth bullet point explains how null fields are handled.

Convert Json string to Java object gives null (null)

Hello i got this Json string
{"NexusResource":{"resourceURI":"http://nexus.ad.hrm.se/nexus/service/local/repositories/snapshots/content/se/hrmsoftware/hrm/hrm-release/16.1-SNAPSHOT/","relativePath":"/se/hrmsoftware/hrm/hrm-release/16.1-SNAPSHOT/","text":"16.1-SNAPSHOT","leaf":false,"lastModified":"2018-04-09 12:23:59.0 UTC","sizeOnDisk":-1}}
I want to convert this to an object of a class named NexusResource that looks like this
public class NexusResource {
#JsonProperty("resourceURI") private String resourceURI;
#JsonProperty("relativePath") private String relativePath;
#JsonProperty("text") private String text;
#JsonProperty("leaf") private Boolean leaf;
#JsonProperty("lastModified") private String lastModified;
#JsonProperty("sizeOnDisk") private Integer sizeOnDisk;
#JsonIgnore private Map<String, Object> additionalProperties = new HashMap<>();
}
i try to convert it with an ObjectMapper
ObjectMapper mapper = new ObjectMapper();
NexusResource resource = mapper.readValue(version, NexusResource.class);
were version is the Json string but when i log resource all i get is null (null) even though version got all the data.
You can configure your ObjectMapper to unwrap the root value, in order to de-serialize into your POJO.
E.g.:
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
See API.
You could also work around that by modifying your POJO (see Karol's answer).
Failure to choose either should result in a com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException being thrown, with message: Unrecognized field "NexusResource".
NexusResource is not a root of your JSON but a key. To make your Java mapping work you should define a wrapping type:
public class NexusResources {
#JsonProperty("NexusResource") private NexusResource root;
...
}
and then use it to map:
ObjectMapper mapper = new ObjectMapper();
NexusResources root = mapper.readValue(version, NexusResources.class);
NexusResource resource = root.getRoot();
The problem is that the JSON does not match the class you are trying to parse. Please notice that the JSON has a field called "NexusResource" that has all the other fields. Whereas the class NexusResource.class just has the fields. Two things you can do. Change the JSON to match NexusResource.class, or create a new class that matches the JSON.
1) Change the json to the following.
{"resourceURI":"http://nexus.ad.hrm.se/nexus/service/local/repositories/snapshots/content/se/hrmsoftware/hrm/hrm-release/16.1-SNAPSHOT/","relativePath":"/se/hrmsoftware/hrm/hrm-release/16.1-SNAPSHOT/","text":"16.1-SNAPSHOT","leaf":false,"lastModified":"2018-04-09 12:23:59.0 UTC","sizeOnDisk":-1}
2) Create new class that actually matches your Json.
class NexusResourceJson {
#JsonProperty("NexusResource ")
NexusResource resource;
public NexusResource getResource() {return resource;}
}
ObjectMapper mapper = new ObjectMapper();
NexusResource resource = mapper.readValue(version, NexusResourceJson.class).getResource();

Parse Json with com.fasterxml.jackson instead of org.json

I was wondering if it is possible to do this exact operation but with the jackson library.
String repo = response.toString();
JSONObject json = new JSONObject (repo);
String nameOfUser = json.getJSONObject(facebookID).getString("name");
Thank you,
Yes. Something like:
ObjectMapper mapper = new ObjectMapper(); // reuse, usually static final
JsonNode ob = mapper.readTree(response.toString()); // or from File, URL, InputStream, Reader
String nameOfUser = ob.path(facebookID).path("name").asText();
// note: '.get()' also works, but returns nulls, 'path()' safer
although even more convenient access is often done using JSON Pointer expressions, like:
String name = ob.at("/person/id").asText();
but I assume facebookID is an id from some other source.
UPDATE: as per comment below, structure you want may actually be POJO like:
public class Response {
public User facebookID;
}
public class User {
public String id;
public String email;
public String first_name;
// ... and so forth: fields and/or getter+setter
}
and then you can bind directly into class like so:
Response resp = mapper.readValue(response.toString(), Response.class);
String name = resp.facebookID.name;
So there's more than one way to do it with Jackson.

Categories

Resources