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

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.

Related

How can I introduce escape characters to my JSON mapper?

I am trying to make a simple thing using com.fasterxml.jackson.databind.ObjectMapper.
I have an object I want to translate to String.
class Car{
String color;
String brand;
//... more class info
}
It is working fine and I get my String as it should but the result looks like this:
{"color: "blue", "brand": "toyota" }
Is it possible to make it look like:
{\"color\": \"blue\", \"brand\", \"toyota\" }
I'm not sure if this breaks the JSON expected format.
I've read the docs and seems like I can use this:
ObjectMapper().factory.setCharacterEscapes(...)
But I'm not sure how to pass it or from which repo. Any ideas?
Use Jackson to generate valid JSON payload and StringEscapeUtils to escape it.
Example code:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.text.StringEscapeUtils;
public class EscapeJsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(new Car("blue", "Toyota"));
String escapedJson = StringEscapeUtils.escapeJson(json);
System.out.println(escapedJson);
}
}
class Car {
String color;
String brand;
// getters, setters, constructor
}
Above code prints:
{\"color\":\"blue\",\"brand\":\"Toyota\"}
Maven dependency:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.8</version>
</dependency>
I am basically trying to make a mapper for an sort of inner object to
match a SNS format https://docs.aws.amazon.com/sns/latest/dg/sns-send-custom-platform-specific-payloads-mobile-devices.html
Here's one of the examples from that page:
{
"GCM":"{\"data\":{\"message\":\"Check out these awesome deals!\",\"url\":\"www.amazon.com\"}}"
}
That's a JSON object with a single field named "GCM" whose value is a string. The content of the string is another JSON object.
Let's take your Car class as an example, and assume you want to generate this JSON as your output:
{
"car": "{\"color\": \"blue\", \"brand\": \"toyota\"}"
}
First you'll need to convert your Car object to a JSON string. Then you create another JSON object and stuff the car's JSON string into a field of this outer object:
String carJson = objectMapper.writeValueAsString(myCar);
Map<String, Object> outerObject = singletonMap("car", carJson);
String finalResult = objectMapper.writeValueAsString(outerObject);
I think that you can use something like JSONObject.quote(json):
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(new Car("blue", "Toyota"));
System.out.println(JSONObject.quote(json));
Output:
"{\"color\": \"blue\", \"brand\", \"toyota\" }"

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();

Retrofit Jackson converter doesn't recognize nested objects

I am using RetrofitJackson2SpiceService to make requests in a service. Jackson is used to parse JSON responses from the API.
But I have one problem.
My User model has following declaration
#JsonIgnoreProperties(ignoreUnknown=true)
public class User {
#JsonProperty("id")
public int id;
#JsonProperty("name")
public String name;
#JsonProperty("surname")
public String surname;
#JsonProperty("email")
public String email;
#JsonProperty("phone")
public String phone;
#JsonProperty("BirthDate")
public String birthDate;
#JsonProperty("token_model")
public Token token;
}
As you may noticed this class has Token as a member
#JsonIgnoreProperties(ignoreUnknown=true)
public class Token {
#JsonProperty("token")
public String token;
#JsonProperty("expiration_time")
public int expirationTime;
#JsonProperty("scope")
public int scope;
}
Server response looks like this
{"id":"36","email":"something#yo.com","name":"Say","surname":"hello","login":"superuser","phone":"4534333","token_model":{"token":"a220249b55eb700c27de780d040dea28","expiration_time":"1444673209","scope":"0"}}
Token is not being parsed, it is always null.
I have tried to convert string manually
String json = "{\"id\":\"36\",\"email\":\"something#yo.com\",\"name\":\"Say\",\"surname\":\"hello\",\"login\":\"superuser\",\"phone\":\"4534333\",\"token_model\":{\"token\":\"a220249b55eb700c27de780d040dea28\",\"expiration_time\":\"1444673209\",\"scope\":\"0\"}}";
ObjectMapper mapper = new ObjectMapper();
User user = null;
try {
user = mapper.readValue(json, User.class);
} catch (IOException e) {
e.printStackTrace();
}
And it works ! Token is parsed correctly without any problems.
Here I have used readValue method accepting String as first parameter, but in Converter
JavaType javaType = objectMapper.getTypeFactory().constructType(type);
return objectMapper.readValue(body.in(), javaType);
Stream version of method is used.
I have tried to return Response instead of User object in the following way
public void onRequestSuccess(Response response) {
super.onRequestSuccess(response);
ObjectMapper objectMapper = new ObjectMapper();
User user = null;
try {
user = objectMapper.readValue(response.getBody().in(), User.class);
} catch (IOException e) {
e.printStackTrace();
}
}
And it works great, like it should, token is parsed correctly.
I have no idea what can cause such problem, I have tried a lot of different combinations of annotations(custom deserializers, unwrap....), custom converters but still the same.
I would be grateful for any help.
Thanks.
I have found the problem exploring source code of Retrofit
The problem is that even if my service is inherited from RetrofitJackson2SpiceService it doesn't use JacksonConverter by default.
GsonConverter used instead.
mRestAdapterBuilder = new RestAdapter.Builder()
.setEndpoint(getServerUrl())
.setConverter(createConverter()) //this line
.setRequestInterceptor(new AuthRequestInterceptor(context))
.setClient(new OkClient(mHttpClient))
.setLogLevel(RestAdapter.LogLevel.FULL)
.setLog(new AndroidLog("RETROFIT"));
Adding converter explicitly while building rest adapter solved the problem.

How do you deserialize JSON in java, using JSON.org

I am using "org.json" for JSON. I am able to serialize any class into a JSON string, using JSONObject. However, I'm not sure how to go the other way. How does one Deserialize a JSON string back into a class instance?
This code works to serialize it. I use JSONObject, and I provide a list of field names as a second argument to the constructor - User.JSONFieldMap().
int randomValue = rnd.nextInt(10000);
String userName = "JavaUnitTest_" + randomValue;
User newUser = new User();
newUser.UserName = userName;
newUser.DisplayName = "Java Unit Test";
newUser.EmailAddress = userName + "#SomeDomainName.com";
JSONObject jsonUser = new JSONObject(newUser, User.JSONFieldMap());
String userStringified = jsonUser.toString();
I'm not sure how, or if it is possible to be able to do something like this:
User myUser = MagicJSONDeserializer.DeserializeIt("{ some JSON string}");
Thanks for any help, I come from a .net/C#/Microsoft background, so Java is very new to me.
That library does not provide such functionality directly. You can use any of hundreds of other Java JSON libraries that do, such as Gson, Jackson, or flexjson.
The indirect way of doing it would be to retrieve each value from the JSON and perform custom deserialization on that value before assigning it to an object field.
Update for someone interested in other solution. It can be achieved using com.fasterxml.jackson.databind as follows:
import com.fasterxml.jackson.databind.ObjectMapper;
String userStr = "{ \"NAME\" : \"John\" }";
User user = new ObjectMapper().readValue(userStr, User.class);
It uses ObjectMapper to convert byte[] or in this caseString to java object. This solution needs to have class User correctly annotated for example with #JsonProperty annotations. Otherwise it won't be able to match json key-values with class attributes.
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
public class User {
#JsonProperty("NAME")
String name;
#JsonGetter("NAME")
public String getName() {
return name;
}
#JsonSetter("NAME")
public void setName(String name) {
this.name = name;
}
}

Parsing JSON object using jQuery and GSON returned by Spring controller

I was looking for some solution around here and I didnt find any correct answer to my question so I would like to ask you.
I have POJO with some simple attribs. and one List of another POJOs.
public class Standard implements Serializable {
private String id;
private String title;
private String description;
private Set<Interpretation> interpretations = new LinkedHashSet<Interpretation>();
}
public class Interpretation implements Serializable {
private String id;
private String title;
private String description;
}
In my controller class, I am returning Standard POJO with GSON.
#RequestMapping(value="/fillStandard", method= RequestMethod.GET)
public #ResponseBody String getStandard(#RequestParam String id) {
Standard s = DAOFactory.getInstance().getStandardDAO().findById(id);
return new Gson().toJson(s);
}
The question is, am I able to get the list of interpretations in my Standard POJO using jQuery ? Something like :
function newStandard() {
$.get("standard/fillStandard.htm", {id:"fe86742b2024"}, function(data) {
alert(data.interpretations[0].title);
});
}
Thanks a lot !
EDIT:
Well, thanks to #Atticus, there is solution of my problem. Hope that it will help somebody.
#RequestMapping(value="/fillStandard", method= RequestMethod.GET, produces="application/json")
public #ResponseBody Standard getStandard(#RequestParam String id) {
Standard s = DAOFactory.getInstance().getStandardDAO().findById(id);
return s;
}
Using #ResponseBody allows you to return the whole POJO, but you need to add produces="application/json" to your #RequestMapping annotation. Then you will be able to catch a returning object as JSON in jQuery like as I supposed.
function newStandard() {
$.get("standard/fillStandard.htm", {id:"idOfStandard"}, function(data) {
alert(data.id); //Standard id
alert(data.interpretations[0].title); //id of Interpretation on first place in array
});
Well you have to create and register your custom serializer.
It goes like this:
//You create your builder that registers your custom serializer with the class you want to serialize
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Standard.class, new StandardSerializer());
//Then you create your Gson object
Gson gson = builder.create();
//Then you pass your object to the gson like
Standard s = DAOFactory.getInstance().getStandardDAO().findById(id);
gson.toJson(s);
Your serializer looks like this:
public class StandardSerializer implements JsonSerializer<Standard>{
#Override
public JsonElement serialize(Standard src, Type typeOfSrc,
JsonSerializationContext context) {
JsonObject obj = new JsonObject();
//You put your simple objects in like this
obj.add("id",new JsonPrimitive(src.getId()));
//You put your complex objects in like this
JsonObject interpretations = new JsonObject();
//Here you need to parse your LinkedHashSet object and set up the values.
//For the sake of simplicity I just access the properties (even though I know this would not compile)
interpretations.add("title", src.getInterpretation().getTitle());
obj.add("interpretations", interpretations);
return obj;
}
}
In this case your Json would look something like:
{"id":"idValue", "title":"titleValue", "description":"descriptionValue", "interpretations":["id":"interpretationIdValue"]}
Now, you can access your data with jQuery like this:
function newStandard() {
$.get("standard/fillStandard.htm", {id:"fe86742b2024"}, function(data) {
alert(data.interpretations.title);
});
}
I hope this helps.
EDIT:
I see that your response gets converted to the declared method argument type which is String (as stated here: 16.3.3.2 Supported method return types). But what you really want is your Standrad POJO converted to JSON. I am not very familiar with Spring but as I have read here (16.3.2.6 Producible Media Types) there is another, maybe easier solution. If you want to return a JSON object, then change the return type of the
getStandard method to Standard instead of String and add produces="application/json" to your #RequestMapping annotation. As far as I have read this should tell Spring that the return type should be converted to JSON. In this case you do not need to use Gson.

Categories

Resources