import java.util.HashMap;
public class JSON {
public String name;
public HashMap<String, String> Credentials = new HashMap<String, String>();
public JSON(String name){
Credentials.put(name, name);
}
}
JSON json = new JSON("Key1");
new Gson().toJson(json);
I get the following value as output.
{"Credentials":{"Key1":"Key1"}}
Now how would i create an JSONObject something like this below using Gson.
You create a POJO that matches your JSON data structure:
public class MyObject {
public HashMap<String,HashMap<String,String>> Credentials;
public HashMap<String, String> Header;
}
Edit for comments below:
This is kinda "data structures 101" but ... you have a JSON Object that boils down to a Hash table that contains two hash tables, the first of which contains two more hash tables.
You can represent this simply as I show above, or you could create all the POJOs and use those:
public class Credentials {
private PrimeSuiteCredential primeSuiteCredential;
private VendorCredential vendorCredential;
// getters and setters
}
public class PrimeSuiteCedential {
private String primeSuiteSiteId;
private String primeSuiteUserName;
...
// Getters and setters
}
public class VendorCredential {
private String vendorLogin;
...
// getters and setters
}
public class Header {
private String destinationSiteId;
...
// getters and setters
}
public class MyObject {
public Credentials credentials;
public Header header;
// getters and setters
}
Building on what #Brian is doing, you just need the auto serialization piece.
What you do is the following, and I have to state, this is with regard to a single object at the moment. You'll have to look through the GSON documentation for more detail on this if you're dealing with a collection of objects at the top level.
Gson gson= new Gson();
Writer output= ... /// wherever you're putting information out to
JsonWriter jsonWriter= new JsonWriter(output);
// jsonWriter.setIndent("\t"); // uncomment this if you want pretty output
// jsonWriter.setSerializeNulls(false); // uncomment this if you want null properties to be emitted
gson.toJson(myObjectInstance, MyObject.class, jsonWriter);
jsonWriter.flush();
jsonWriter.close();
Hopefully that will give you enough context to work with. Gson should be smart enough to figure out your properties and give them sensible names in the output.
Related
I am using JackSon to parse the following JSON:
{
"AwardID": "1111111",
"AwardTitle": "Test Title",
"Effort":
"[
{
"PersonFirstName": "Jon",
"PersonLastName": "Snow"
}
]"
}
I would like to flatten this to be used in the following class:
public class Award {
private String awardId;
private String awardTitle;
private String personFirstName;
private String personLastName;
}
I have tried the following and have gotten the first two values, but I haven't been able to get the values from Effort trying to use JsonUnwrapped. I noted that it doesn't work with arrays, but I am trying the objectMapper.configure(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS, true) configuration in the main method used to get the values.
public class Award {
#JsonProperty("AwardID")
private String awardId;
#JsonProperty("AwardTitle")
private String awardTitle;
#JsonUnwrapped
private Effort effort;
}
public class Effort {
private String personFirstName;
private String personLastName;
}
Note that I only expect one value in the Effort array from the API response at this time.
What is recommended to try next? Thank you!
The easiest way is having a List<Effort> if you have a JSON Array.
If there is always 1 item for Effort, the returning JSON should not have Effort as a JSON Array and instead should be a JSON Object.
But if you can only handle it codewise, you can have something like this (Note that there should always contain one item in Effort, otherwise it will throw Exception):
public class Award {
#JsonProperty("AwardID")
private String awardId;
#JsonProperty("AwardTitle")
private String awardTitle;
#JsonProperty("Effort")
private Effort effort;
}
public class Effort {
#JsonProperty("PersonFirstName")
private String personFirstName;
#JsonProperty("PersonLastName")
private String personLastName;
}
And your ObjectMapper needs to be enabled with DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS as well:
ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS);
Award award = mapper.readValue(rawJson, Award.class); // rawJson is your JSON String
And it should have the following output:
Award(awardId=1111111, awardTitle=Test Title, effort=Effort(personFirstName=Jon, personLastName=Snow))
Note that the annotation #JsonUnwrapped can only apply on JSON Object, not JSON Array:
Value is serialized as JSON Object (can not unwrap JSON arrays using this mechanism)
I want to use Jackson to implement toString() to return the JSON representation of an object, but I do not want to use any Jackson annotation in my code.
I tried an implementation along the lines of:
public String toString()
{
Map<String,Object> ordered = ImmutableMap.<String, Object>builder().
put("createdAt", createdAt.toString()).
put("address", address.toString()).
build();
ObjectMapper om = new ObjectMapper();
om.enable(SerializationFeature.INDENT_OUTPUT);
try
{
return om.writeValueAsString(object);
}
catch (JsonProcessingException e)
{
// Unexpected
throw new AssertionError(e);
}
}
This works well for simple fields but if "address" has its own fields then instead of getting this:
{
"address" : {
"value" : "AZ4RPBb1kSkH4RNewi4NXNkBu7BX9DmecJ",
"tag" : null
}
I get this output instead:
{
"address" : "{\n\"value\" : \"AZ4RPBb1kSkH4RNewi4NXNkBu7BX9DmecJ\",\n \"tag\" : null"
}
In other words, the address value is being treated like a String as opposed to a JsonNode.
To clarify:
On the one hand, I want to control how simple class fields are converted to String. I don't want to use Jackson's built-in converter.
On the other hand, for complex fields, returning a String value to Jackson leads to the wrong behavior.
I believe that I could solve this problem by adding a public toJson() method to all my classes. That method would return a Map<String, JsonNode>, where the value is a string node for simple fields and the output of toJson() for complex fields. Unfortunately, this would pollute my public API with implementation details.
How can I achieve the desired behavior without polluting the class's public API?
UPDATE: I just saw an interesting answer at https://stackoverflow.com/a/9599585/14731 ... Perhaps I could convert the String value of complex fields back to JsonNode before passing them on to Jackson.
I think you should implement two methods in each class - one to dump data, second to build JSON out of raw data structure. You need to separate this, otherwise you will nest it deeper and deeper every time you encapsulate nested toString() calls.
An example:
class Address {
private BigDecimal yourField;
/* …cut… */
public Map<String, Object> toMap() {
Map<String, Object> raw = new HashMap<>();
raw.put("yourField", this.yourField.toPlainString());
/* more fields */
return raw;
}
#Override
public String toString() {
// add JSON processing exception handling, dropped for readability
return new ObjectMapper().writeValueAsString(this.toMap());
}
}
class Employee {
private Address address;
/* …cut… */
public Map<String, Object> toMap() {
Map<String, Object> raw = new HashMap<>();
raw.put("address", this.address.toMap());
/* more fields */
return raw;
}
#Override
public String toString() {
// add JSON processing exception handling, dropped for readability
return new ObjectMapper().writeValueAsString(this.toMap());
}
}
I have a Java web service with a Jersey REST endpoint that returns a list of Restaurant POJOs as JSON objects (see Restaurant class below). The endpoint looks like this
/api/restaurants
and returns all the data tied to the Restaurant class. However, I want to add another, more lean endpoint that looks like this
/api/restaurants/name
which returns only the id and name of the Restaurant POJO for all restaurants. Is there a nice way to do this in Jersey out of the box (e.g. specify the fields you want from a POJO for specific endpoints)?
The corresponding POJO looks something like this:
#XmlRootElement
public class Restaurant {
// Members
private Long id;
private String name;
private List<Menu> menus;
...
// Constructors
public Restaurant() {}
...
// Getters and setters
...
}
If you need anything else, please don't hesitate to let me know! Thanks!
Yes, Jersey has support for selecting the elements that are included in serialized XML/JSON. Take a look at the entity filtering section of the manual.
Essentially, you annotate particular #XmlElements in your POJO with custom annotations. In your REST resource, you pass the annotation to Jersey when you build the Response.
Note that this only works if you use EclipseLink MOXy as your JAXB provider.
First of all, I am guessing that your api is going to be
/api/restaurants/{restaurantId}/name
and not
/api/restaurants/name
And in regards to your question of jersey having this feature out the box, I am not certain about it. Although, this is a much easier way to handle this.
Inside your POJO you can do something like this:
public class Restaurant {
// Members
private Long id;
private String name;
private List<Menu> menus;
...
// Constructors
public Restaurant() {}
...
// Getters and setters
...
// For getting only id and name
public Map getIdAndName()
{
Map<Object, Object> map = new HashMap<>();
map.put("id", this.id);
map.put("name", this.name);
return map;
}
// For getting just a list of menu and name
public Map getNameAndMenu()
{
Map<Object, Object> map = new HashMap<>();
map.put("menus", this.menus);
map.put("name", this.name);
return map;
}
And in your service class you can pretty much use something like this
#Path("/api/restaurants/{restaurantId}/name")
#Produces("application/json")
public String getRestaurantName(#PathParam("restaurantId") String restaurantId)
{
// GET RESTAURANT
Restaurant restaurant = getRestaurant(restaurantId);
Gson gson = new Gson();
// CONVERT TO JSON AND RETURN (or let jersey do that serializable, whichever way is preferable to you.
return gson.toJson(restaurant.getIdAndName());
}
Hope this helps!
I need strict compliance with the order of the elements in my xml document. If I use XmlHttpContent serializer to form xml content, fields sort alphabetically.
Is there any way to specify explicitly order of the elements in xml? Or are there other ways to create and post http requests with the xml body?
I know this answer isn't ideal but I recently came across this issue when trying to use the http client library for serialisation to xml. The solution I've found that works is to have my DTO classes provide a method to convert them into a sorted map of some kind.
In my case this is an ImmutableMap<String, Object> as I'm also using Guava but any map with controllable order will do. The basic idea is to work with the java objects to construct your data but then when the time comes to serialise them you serialise the map instead.
public interface OrderedXml {
ImmutableMap<String, Object> toOrderedMap();
}
public class Parent implements OrderedXml {
#Key("First") String first;
#Key("Second") String second;
#Key("Child") Child third;
#Override
public ImmutableMap<String, Object> toOrderedMap() {
return ImmutableMap.of(
// the order of elements in this map will be the order they are serialised
"First", first,
"Second", second,
"Child", third.toOrderedMap()
);
}
}
public class Child implements OrderedXml {
#Key("#param1") String param1;
#Key("#param2") String param2;
#Key("text()") String value;
#Override
public ImmutableMap<String, Object> toOrderedMap() {
return ImmutableMap.of(
// the same goes for attributes, these will appear in this order
"#param1", param1,
"#param2", param2,
"text()", value
);
}
}
public class Main {
public static void main(String[] args) {
// make the objects
Parent parent = new Parent();
parent.first = "Hello";
parent.second = "World";
parent.child = new Child();
parent.child.param1 = "p1";
parent.child.param2 = "p2";
parent.child.value = "This is a child";
// serialise the object to xml
String xml = new XmlNamespaceDictionary()
.toStringOf("Parent", parent.toOrderedXml()); // the important part
System.out.println(xml); // should have the correct order
}
}
I know this solution isn't ideal but at least you can reuse the toOrderedXml to make a nice toString :-).
I'm trying to use GSON 2.2.2 (for the very first time) to map JSON into a Java POJO. I'm hitting a 3rd party RESTful web service and this is an example of the JSON I'm getting back:
{
"response": {
"job":{
"eta":-1,
"status":"approved",
"mt":1,
"lc_tgt":"fr",
"body_src":"Please translated me.",
"body_tgt":"S'il vous plaît traduire moi.",
"unit_count":3,
"tier":"machine",
"credits":0,
"ctime":"2013-02-07 14:56:12.391963",
"lc_src":"en",
"slug":"0",
"job_id":"NULL"
}
},
"opstat":"ok"
}
The POJO I'm trying to map this into is:
public class Job {
// correlates to "eta"
private int eta;
// correlates to "body_src"
private String sourceBody;
// correlates to "ctime"
private java.util.Date creationTimestamp;
// Getters and setters for all 3 properties
}
When I run the following code, I don't get any exceptions, but the print statement just prints "null":
// Hit the 3rd party service and get the JSON (example above).
JSONObject json = hitRestfulWebService();
Gson gson = new Gson();
// json.toString = "{response":{"job":{ ..."
Job job = gson.fromJson(json.toString(), Job.class);
System.out.println(job.getSourceBody());
My only guess is that GSON can't figure out how to map the 3 JSON fields to my 3 Job properties. Can someone help me figure out what this mapping needs to be? Thanks in advance.
You can use annotations to define, which json field gets mapped to which object member, e.g.:
class SomeClass
{
#SerializedName("body-src")
String myString1;
#SerializedName("header-src")
String myString2;
...
public class Response{
private Job job;
//generate setter and getter
}
public class Job {
// correlates to "eta"
private int eta;
// correlates to "body_src"
private String sourceBody;
// correlates to "ctime"
private java.util.Date creationTimestamp;
// Getters and setters for all 3 properties
}
now in Gson
JSONObject json = hitRestfulWebService();
Gson gson = new Gson();
// json.toString = "{response":{"job":{ ..."
Job job = gson.fromJson(json.toString(), Response.class);
use not response but response.job
not
{ "response": {..
use
{ "eva": ..
this may help;
String a = "{\"response\": {\"job\":{\"eta\":-1,\"status\":\"approved\",\"mt\":1,\"lc_tgt\":\"fr\",\"body_src\":\"Please translated me.\",\"body_tgt\":\"S'il vous plaît traduire moi.\",\"unit_count\":3,\"tier\":\"machine\",\"credits\":0,\"ctime\":\"2013-02-07 14:56:12.391963\",\"lc_src\":\"en\",\"slug\":\"0\",\"job_id\":\"NULL\"}},\"opstat\":\"ok\"}";
Job j = I.gson().fromJson(
((JsonObject) ((JsonObject) new JsonParser().parse(a)).get("response")).get("job"), Job.class);
System.out.println(j.getEta());