I have java class like:
public class Sample{
int foo=5;
int bar=6;
}
now I want to generate JSON object but without bar field:
{"foo":5}
What is a best way to accomplish that?
Should I compose JSON string manually, or can I use some library, or generator?
Should I compose JSON string manually
Avoid this, it's all to easy to make invalid json this way. Use of a library ensures proper escaping of characters that would otherwise break the output.
Gson ignores transient fields:
public class Sample {
private int foo = 5;
private int transient bar = 6;
}
Gson gson = new Gson();
Or you can choose which to include with Expose attribute:
public class Sample {
#Expose private int foo = 5;
private int bar = 6;
}
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
Then whichever approach, do this:
String json = gson.toJson(obj);
To get your desired {"foo":5}
You can use the Jackson to solve your problem. Follow the below step -
Step 1 - Make a method which will convert Java object to Json
public class JsonUtils {
public static String javaToJson(Object o) {
String jsonString = null;
try {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.UNWRAP_ROOT_VALUE,true);
jsonString = objectMapper.writeValueAsString(o);
} catch (JsonGenerationException e) {
logger.error(e);
} catch (JsonMappingException e) {
logger.error(e);
} catch (IOException e) {
logger.error(e);
}
return jsonString;
}
}
Step 2 Model Class
package com.javamad.model;
import org.codehaus.jackson.annotate.JsonIgnore;
public class Sample{
int foo=5;
public int getFoo() {
return foo;
}
public void setFoo(int foo) {
this.foo = foo;
}
#JsonIgnore
public int getBar() {
return bar;
}
public void setBar(int bar) {
this.bar = bar;
}
int bar=6;
}
Step 3 Convert your java class to json
Sample sample = new Sample()
JsonUtils.javaToJson(sample);
you can try Gson, JSON library, to convert object to/from json.
these two methods are helpfull:
toJson() – Convert Java object to JSON format
fromJson() – Convert JSON into Java object
Gson gson = new Gson();
// convert java object to JSON format,
// and returned as JSON formatted string
String json = gson.toJson(obj);
Related
I have JSON response which looks like that:
{
"response":[
"Some number (for example 8091)",
{
"Bunch of primitives inside the first JSONObject"
},
{
"Bunch of primitives inside the second JSONObject"
},
{
"Bunch of primitives inside the third JSONObject"
},
... (and so on)
]
}
So it's an array with first integer element and other elements are JSONObject.
I don't need integer element to be parsed. So how do I handle it using GSON?
I would solve this problem by creating a custom JsonDeserializer and registering it to your Gson instance before parsing. This custom deserializer would be set up to handle both ints and real objects.
First you need to build up a series of model objects to represent the data. Here's a template for what that might look like:
private static class TopLevel {
#SerializedName("response")
private final List<ResponseElement> elements;
private TopLevel() {
this.elements = null;
}
}
private static class ResponseInteger implements ResponseElement {
private final int value;
public ResponseInteger(int value) {
this.value = value;
}
}
private static class ResponseObject implements ResponseElement {
#SerializedName("id")
private final String id;
#SerializedName("text")
private final String text;
private ResponseObject() {
this.id = null;
this.text = null;
}
}
private interface ResponseElement {
// marker interface
}
TopLevel and ResponseObject have private constructors because they are going to let Gson set their fields using reflection, while ResponseInteger has a public constructor because we're going to manually invoke it from our custom deserializer.
Obviously you will have to fill out ResponseObject with the rest of its fields.
The deserializer is relatively simple. The json you posted contains only two kinds of elements, and we'll leverage this. Each time the deserializer is invoked, it checks whether the element is a primitive, and returns a ResponseInteger if so (or a ResponseObject if not).
private static class ResponseElementDeserializer implements JsonDeserializer<ResponseElement> {
#Override
public ResponseElement deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json.isJsonPrimitive()) {
return new ResponseInteger(json.getAsInt());
}
else {
return context.deserialize(json, ResponseObject.class);
}
}
}
To use this deserializer, you'll have to register it with Gson using the GsonBuilder object.
private static Gson getGson() {
return new GsonBuilder()
.registerTypeAdapter(ResponseElement.class, new ResponseElementDeserializer())
.create();
}
And that's it. Now you can use this Gson object to easily parse TopLevel objects!
public void parseJson() {
TopLevel t = getGson().fromJson(json, TopLevel.class);
for (ResponseElement element : t.elements) {
System.out.println(element);
}
}
8061
[450602: Поздравляем!]
[451700: С реакцией чата и рассуждениями Папани после рипа..]
[451578: Помним...Любим...Скорбим...<br>2107 забирает лучших]
[451371: Земля тебе пухом братишка]
[451332: Доигрался, минус 900 экзов<br><br>R I P]
[451269: ]
[451242: https://www.twitch.tv/arthas подрубка<br><br>evilpapech.ru - скидка 30% на футболки!]
[451217: ]
[451181: или так це жерстко?]
[451108: ]
I used these toString() methods, which I omitted above for brevity:
#Override
public String toString() {
return Integer.toString(value);
}
#Override
public String toString() {
return "[" + id + ": " + text + "]";
}
Try this
Gson gson = new Gson();
// Reading from a file.
Example example = gson.fromJson(new FileReader("D:\\content.json"), Example.class);
POJO
package com.example;
public class Example {
private List<Integer> response = null;
public List<Integer> getResponse() {
return response;
}
public void setResponse(List<Integer> response) {
this.response = response;
}
}
Basically this structure is the wrong format for JSON data.
You need to remove the number, or put this number as a field in the same object like the one below (call ObjectA) and consider this is an array of ObjectA.
Then everything should work well. Try the code below:
public class Response {
#SerializedName("response")
#Expose
public List<ObjectA> objectA = null;
}
public class ObjectA {
#SerializedName("value")
#Expose
public Integer value;
#SerializedName("description")
#Expose
public String description;
}
Response response = new Gson().fromJson(responseString, Response.class);
Please use below ValueObject format which doesn't parse first integer element
public class ResponseVO {
public List<Response> response = new ArrayList();
public class Response {
public final long id;
public final long from_id;
...
}
}
I am using Jackson for de/serialization in my app.
I have a situation where I need to convert a JSON string to one of my 3 classes. In case the string can't be converted to either one of 3 classes, it will considered to be an unrecognized case.
However, if the schema of json string and the provided class in mapper.readValue(jsonString,MyClass1.class) does not match, it throws an UnrecognizedPropertyException.
Currently I am using something like below, but it seems to be pretty messy.
try {
obj = mapper.readValue(jsonString, MyClass1.class);
} catch (UnrecognizedPropertyException e1) {
try {
obj = mapper.readValue(jsonString, MyClass2.class);
} catch (UnrecognizedPropertyException e2) {
try {
obj = mapper.readValue(jsonString, MyClass3.class);
} catch (Exception e) {
//handle unrecognized string
}
} catch (Exception e) {
//handle unrecognized string
}
} catch (Exception e) {
//handle unrecognized string
}
Is this how it needs to be done or is there any other alternative? Is there any way to configure the mapper to return null in case of unrecognized properties, as that would result in creating a simple series if blocks instead of nested try-catch blocks?
You can try this method to do deserialization thing. this will return null on UnrecognizedPropertyException:
private <T> T deserialize(ObjectMapper mapper, Class<T> type, String jsonString) {
T t = null;
try {
t = mapper.readValue(jsonString, type);
} catch (UnrecognizedPropertyException e) {
//handle unrecognized string
}catch (IOException e) {
//handle under errors
}
return t;
}
If jsonString is generated by you, you can consider to add type info and then use it to convert deserialized object. You could refer to this post for how to do it.
If jsonString is generated by other services beyond your control, then there's no type info you can get so you can only try it one by one, #Sachin Gupta's answer would be a nice choice.
I'd like to provide an additional option: define an all-in-one entity including all fields of MyClass1, MyClass2 and MyClass3, and make MyClass1, MyClass2 and MyClass3 be separated wrapper and only expose related fields for each. Code as follows:
Class AllInOne:
public class AllInOne {
protected String a;
protected String b;
protected String c;
public A asA() {
return new A(this);
}
public B asB() {
return new B(this);
}
public C asC() {
return new C(this);
}
}
Class A:
public class A {
private AllInOne allInOne;
public A(AllInOne allInOne) {
this.allInOne = allInOne;
}
public String getA() {
return allInOne.a;
}
}
Class B:
public class B {
private AllInOne allInOne;
public B(AllInOne allInOne) {
this.allInOne = allInOne;
}
public String getB() {
return allInOne.b;
}
}
Class C:
public class C {
private AllInOne allInOne;
public C(AllInOne allInOne) {
this.allInOne = allInOne;
}
public String getC() {
return allInOne.c;
}
}
Test code:
public class Main {
public static void main(String[] args) throws IOException {
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
String jsonA = "{\"a\":\"a value\"}";
String jsonB = "{\"b\":\"b value\"}";
String jsonC = "{\"c\":\"c value\"}";
needTypeA(om.readValue(jsonA, AllInOne.class).asA());
needTypeB(om.readValue(jsonB, AllInOne.class).asB());
needTypeC(om.readValue(jsonC, AllInOne.class).asC());
}
private static void needTypeA(A a) {
System.out.println(a.getA());
}
private static void needTypeB(B b) {
System.out.println(b.getB());
}
private static void needTypeC(C c) {
System.out.println(c.getC());
}
}
With implementation like this, we erased the specific type info at deserialization step, and bring it back at the moment we really need/use it. And as you can see there's not too much extra code, because what we actually did is just moving all fields declaration together, and added couple methods.
Notes:
I declare fields in AllInOne to be protected, putting all POJO class in the same package will make A, B and C be able to access them directly, but not for other classes outside.
Setting om.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); to make jackson deserialize by field, so that we can remove duplicate setter and getter from AllInOne class
If you do need to know the type info, you could add methods like isA inside AllInOne based on the fields info
If json contains some define property, than you can try to use #JsonTypeInfo and #JsonSubTypes. Classes MyClass1, ... must implement this interface. Also I don`t remember exactly how to map unknown implementations to null.
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY, // level of define property
property = <property_name>,
visible = true,
defaultImpl = NoClass.class)
#JsonSubTypes({#JsonSubTypes.Type(value = <interface-impl>.class, name = <property_value>)})
private <interface> value;
// getters and setters
I am trying to parse Json object which is;
{
"results":[
{
"face":{
"id":361122.0,
"photo_hash":"0a2aaff34fd576fc1caf711d88cbfd53",
"x1":699,
"x2":1020,
"y1":271,
"photo":" ",
"thumbnail":" ",
"meta":"",
"timestamp":"2016-07-28T08:50:43.710183",
"y2":592
},
"confidence":0.93187
},
{
"face":{
"id":361260.0,
"photo_hash":"767bf4df0c8a04361aaf5e6b74eb4d8c",
"x1":-25,
"x2":147,
"y1":10,
"photo":" ",
"thumbnail":" ",
"meta":"",
"timestamp":"2016-07-28T15:13:09.086390",
"y2":165
},
"confidence":0.926754
}
]
}
And I am using such code for parsing confidence and thumbnail :
resultParams[i].confidence = jsonObject.getJSONArray("results").getJSONObject(i).getString("confidence");
resultParams[i].thumbnail = jsonObject.getJSONArray("results").getJSONObject(i).getJSONObject("face").getString("thumbnail");
However it gives exception "java.lang.NullPointerException: Attempt to write to field on a null object reference"
Could you please help me how to successfully parse it?
To give this an answer:
"java.lang.NullPointerException: Attempt to write to field on a null object reference"
Means your left side is the problem. resultParams[i] is most probably null.
If you know what kind of json-object will you receive(or maybe you have an API), you can make an object of this class by for example Jackson library. And then get access to "face" object with its getter.
yourObject.getResults().get(i).getFace().getThumbnail();
Firstly based on the JSON response you create your model object.
You can make use of GSON for converting the whole content into object.
This can be acheived using other libaries too.
So here are the Model objects for your JSON
import java.util.Date;
import java.util.List;
class Result {
private List<PersonDetails> results;
// generate setter and getter
}
class PersonDetails
{
private ImageDetail face;
private Float confidence;
// generate setter and getter
}
class ImageDetail
{
private Long id;
private String photo_hash;
private Integer x1,x2,y1,y2;
private String thumbnail;
private String meta;
private String photo;
private Date timestamp;
// generate setter and getter
}
Now use GSON to convert your JSON.
public class JsonTransaformer1 {
#SuppressWarnings("unchecked")
public static void main(String[] args) {
String text = "Place your JSON Response as input that you posted";
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new GsonUTCdateAdapter()).create();
Result obj = gson.fromJson(text, Result.class);
System.out.println(obj.getResults().size());
System.out.println(obj.getResults().get(0).getFace().getId());
System.out.println(obj.getResults().get(0).getConfidence());
}
}
As the Date format that is present in your JSON response is different we need to register the Adapter to parse the date.
Look into this link for parsing
Java Date to UTC using gson
class GsonUTCdateAdapter implements JsonSerializer<Date>,JsonDeserializer<Date> {
private final DateFormat dateFormat;
public GsonUTCdateAdapter() {
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US); //This is the format I need
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); //This is the key line which converts the date to UTC which cannot be accessed with the default serializer
}
#Override public synchronized JsonElement serialize(Date date,Type type,JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive(dateFormat.format(date));
}
#Override public synchronized Date deserialize(JsonElement jsonElement,Type type,JsonDeserializationContext jsonDeserializationContext) {
try {
return dateFormat.parse(jsonElement.getAsString());
} catch (ParseException e) {
throw new JsonParseException(e);
}
}
}
Now running the main you will get the Object representation of JSON.
My json string looks like the following:
{
"text": ["foo",1,"bar","2",3],
"text1": "value1",
"ComplexObject": {
.....
}
}
I have a pojo defined like this:
class MyPojo {
List<String> text;
String text1;
ComplexObject complexObject;
}
I use google gson and am able to get my java object populated properly. The problem here is that the field text is an array of mixed types (string and int). So all the entries there are converted into String and i am not able to figure out which entries in the array is a string vs int. I cant use parseInt since the entries in the original array may have "2" as well as 3.
Is there a way for me to get the right instance type of the fields in my array after converting into java object.
SOLUTION
So i implemented the solution using gson the round about way using the JsonDeserializer. And then i tried using jackson. Guess what jackson supports serializing/deserializing the mixed array type by preserving the data types.
ObjectMapper mapper = new ObjectMapper();
MyPojo gmEntry = mapper.readValue(json, new TypeReference<MyPojo >(){});
And i can basically fetch the List<Object> and do an instanceof to check for the datatype.
Shame on you gson!!
By having a custom class and adding a type adapter u can manipulate the string (json.toString() returns with the '"' quotes, so you can see if its a string or not.
Output: (the classes seem correct)
class test.Main$StringPojo pojo{object=foo}
class test.Main$IntPojo pojo{object=1}
class test.Main$StringPojo pojo{object=bar}
class test.Main$StringPojo pojo{object=2}
class test.Main$IntPojo pojo{object=3}
public static void main(final String[] args){
String str = "{\n" +
" \"text\": [\"foo\",1,\"bar\",\"2\",3],\n" +
" \"text1\": \"value1\" }";
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(pojo.class, new JsonDeserializer<pojo>() {
#Override
public pojo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
try {
return new IntPojo(Integer.parseInt(json.toString()));
} catch (Exception e) {
return new StringPojo(json.getAsString());
}
}
});
MyPojo myPojo = builder.create().fromJson(str, MyPojo.class);
for (pojo pojo : myPojo.text) {
System.out.println(pojo.getClass() + " " + pojo.object);
}
}
public static abstract class pojo{
protected Object object;
public pojo() {
}
#Override
public String toString() {
return "pojo{" +
"object=" + object +
'}';
}
}
public static class StringPojo extends pojo{
public StringPojo(String str) {
object = str;
}
}
public static class IntPojo extends pojo{
public IntPojo(int intt) {
this.object = intt;
}
}
public static class MyPojo {
List<pojo> text;
String text1;
}
As you wrote - you defined: List<String> text; but that list also contains integers.
Java is strongly typed, please consider to either declare the List as List<Object> (less preferable) or creating a JSON list that contains only a single type of variable (more preferable).
You can create an abstract class ItemType (for use as array item type) and inherits from it two wrapper classes: one for int type and another for string type.
abstract class ItemType {
protected Object value;
}
class IntType extends ItemType {
IntType(Integer value){
this.value = value;
}
}
class StringType extends ItemType {
IntType(String value){
this.value = value;
}
}
Try this List<ItemType> text;
The above situation can be achived by using TypeAdapter of Gson API.
Please follow : https://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Collection-with-Objects-of-Arbitrary-Types
Not sure if this is what you need, but this is the code I use for parsing JSON.
static public void newsParser(String urlString, String targetObject) throws FileNotFoundException, IOException
{
URL url = new URL(urlString);
JSONParser parser=new JSONParser();
BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
Object obj;
try
{
obj = parser.parse(br);
//JSONObject jsonObject = (JSONObject) obj;
JSONArray jsonArray = (JSONArray) obj;
Iterator<?> i = jsonArray.iterator();
while (i.hasNext())
{
slide = (JSONObject) i.next();
newsInfo = (String)slide.get(targetObject);
System.out.println(newsInfo);
newsTitles.add(newsInfo);
}
}
catch (ParseException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Seems like Gson.toJson(Object object) generates JSON code with randomly spread fields of the object. Is there way to fix fields order somehow?
public class Foo {
public String bar;
public String baz;
public Foo( String bar, String baz ) {
this.bar = bar;
this.baz = baz;
}
}
Gson gson = new Gson();
String jsonRequest = gson.toJson(new Foo("bar","baz"));
The string jsonRequest can be:
{ "bar":"bar", "baz":"baz" } (correct)
{ "baz":"baz", "bar":"bar" } (wrong sequence)
You'd need to create a custom JSON serializer.
E.g.
public class FooJsonSerializer implements JsonSerializer<Foo> {
#Override
public JsonElement serialize(Foo foo, Type type, JsonSerializationContext context) {
JsonObject object = new JsonObject();
object.add("bar", context.serialize(foo.getBar());
object.add("baz", context.serialize(foo.getBaz());
// ...
return object;
}
}
and use it as follows:
Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class, new FooJsonSerializer()).create();
String json = gson.toJson(foo);
// ...
This maintains the order as you've specified in the serializer.
See also:
Gson User Guide - Custom serializers and deserializers
If GSON doesn't support definition of field order, there are other libraries that do. Jackson allows definining this with #JsonPropertyOrder, for example. Having to specify one's own custom serializer seems like awful lot of work to me.
And yes, I agree in that as per JSON specification, application should not expect specific ordering of fields.
Actually Gson.toJson(Object object) doesn't generate fields in random order. The order of resulted json depends on literal sequence of the fields' names.
I had the same problem and it was solved by literal order of properties' names in the class.
The example in the question will always return the following jsonRequest:
{ "bar":"bar", "baz":"baz" }
In order to have a specific order you should modify fields' names, ex: if you want baz to be first in order then comes bar:
public class Foo {
public String f1_baz;
public String f2_bar;
public Foo ( String f1_baz, String f2_bar ) {
this.f1_baz = f1_baz;
this.f2_bar = f2_bar;
}
}
jsonRequest will be { "f1_baz ":"baz", "f2_bar":"bar" }
Here's my solution for looping over json text files in a given directory and writing over the top of them with sorted versions:
private void standardizeFormat(File dir) throws IOException {
File[] directoryListing = dir.listFiles();
if (directoryListing != null) {
for (File child : directoryListing) {
String path = child.getPath();
JsonReader jsonReader = new JsonReader(new FileReader(path));
Gson gson = new GsonBuilder().setPrettyPrinting().registerTypeAdapter(LinkedTreeMap.class, new SortedJsonSerializer()).create();
Object data = gson.fromJson(jsonReader, Object.class);
JsonWriter jsonWriter = new JsonWriter(new FileWriter(path));
jsonWriter.setIndent(" ");
gson.toJson(data, Object.class, jsonWriter);
jsonWriter.close();
}
}
}
private class SortedJsonSerializer implements JsonSerializer<LinkedTreeMap> {
#Override
public JsonElement serialize(LinkedTreeMap foo, Type type, JsonSerializationContext context) {
JsonObject object = new JsonObject();
TreeSet sorted = Sets.newTreeSet(foo.keySet());
for (Object key : sorted) {
object.add((String) key, context.serialize(foo.get(key)));
}
return object;
}
}
It's pretty hacky because it depends on the fact that Gson uses LinkedTreeMap when the Type is simply Object. This is an implementation details that is probably not guaranteed. Anyway, it's good enough for my short-lived purposes...