JSON text to Java conversion issue with random number generation - java

For example my JSON text is coming like this.
"pages":{"42010":{"pageid":42010,"ns":0,"title":"Queen (band)"}}
Because everytime my json text is coming with different number which is inside pages tag.
How do i convert this to Java equivalent class?
Currently my generated java class is something like this.
#Generated("org.jsonschema2pojo")
public class Pages {
#SerializedName("42010")
#Expose
private _42010 _42010;
}
That _42010 class contains the inner fields like "pageid":42010,"ns":0,"title":"Queen (band)", since i am getting everytime new number inside pages, its not working. its working only for the specific json text.

You can use a custom deserialiser that ignored the changing number. For example:
package jacksonTest;
import java.io.IOException;
import java.lang.reflect.Type;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
public class CustomDeserialiser {
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
String json = "{\"42010\":{\"pageid\":42010,\"ns\":0,\"title\":\"Queen (band)\"}}";
String json2 = "{\"12345\":{\"pageid\":12345,\"ns\":0,\"title\":\"Queen (band)\"}}";
Gson g = new GsonBuilder().registerTypeAdapter(Pages.class, new PagesDeserialiser()).create();
Pages fromJson = g.fromJson(json, Pages.class);
System.out.println(fromJson);
fromJson = g.fromJson(json2, Pages.class);
System.out.println(fromJson);
}
public static class PagesDeserialiser implements JsonDeserializer<Pages> {
#Override
public Pages deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws com.google.gson.JsonParseException {
JsonObject object = json.getAsJsonObject();
Pages p = new Pages();
object.entrySet().forEach( e -> {
JsonObject tmp = e.getValue().getAsJsonObject();
if(tmp.get("pageid") != null) {
// right object
p._42010 = new _42010();
p._42010.ns = tmp.get("ns").getAsInt();
p._42010.pageid = tmp.get("pageid").getAsInt();
p._42010.title = tmp.get("title").getAsString();
}
});
return p;
}
}
public static class Pages {
_42010 _42010;
#Override
public String toString() {
return _42010.toString();
}
}
public static class _42010 {
int pageid;
int ns;
String title;
#Override
public String toString() {
return title + " " + pageid + " " + ns;
}
}
}
The deserialiser for type pages simply checks the entries to find the one that contains a pageId and then populates the class.
Running my test gives you:
Queen (band) 42010 0
Queen (band) 12345 0
I am assuming that you are using Gson as your json library.
Regards,
Artur

Why do not use an JSON library like jackson or org.json?
Make your json correct like
{
"pages":{
"42010":{
"pageid":42010,
"ns":0,
"title":"Queen (band)"
}
}
}
And you will be able to use it like :
JSONObject jsonObjet = new JSONObject(yourJson);
jsonObjet.get("pages");

Ideally it should be using Map.
This helps in forming the values as Map<Integer, Pojo>.
Lets say
public class Pojo{
private int pageid;
private String title;
private int ns;
// getter and setter
}
This suffices the requirement of holding the random digits, generated at runtime,

Related

How to write an interface type adapter for gson without infinite recursion/stackoverflow

I'm trying to write a generic handler for de/serializing interfaces using Gson and getting stack overflow. I've followed a couple of examples at https://technology.finra.org/code/serialize-deserialize-interfaces-in-java.html and https://paul-stanescu.medium.com/custom-interface-adapter-to-serialize-and-deserialize-interfaces-in-kotlin-using-gson-8539c04b4c8f (which seem to be duplicates of each other). If I run these, serializing a simple class, I get stack overflow. I'm using Gson 2.8.5. I guess its fairly clear that it is trying to call the type adapter again when trying to get the value for the DATA element. Searched around, but haven't seen anything. Any help is much appreciated. Thanks.
import java.lang.reflect.Type;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
public class InterfaceAdapter<INTERFACE> implements JsonSerializer<INTERFACE>, JsonDeserializer<INTERFACE> {
private static final String CLASSNAME = "CLASSNAME";
private static final String DATA = "DATA";
public INTERFACE deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
JsonObject jsonObject = jsonElement.getAsJsonObject();
JsonPrimitive prim = (JsonPrimitive) jsonObject.get(CLASSNAME);
String className = prim.getAsString();
Class<INTERFACE> klass = getObjectClass(className);
return jsonDeserializationContext.deserialize(jsonObject.get(DATA), klass);
}
public JsonElement serialize(INTERFACE jsonElement, Type type, JsonSerializationContext jsonSerializationContext) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty(CLASSNAME, jsonElement.getClass().getName());
jsonObject.add(DATA, jsonSerializationContext.serialize(jsonElement));
return jsonObject;
}
public Class getObjectClass(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new JsonParseException(e.getMessage());
}
}
public static class Dummy {
int a= 1;
}
public static void main(String args[]) {
Gson gson = new GsonBuilder().registerTypeHierarchyAdapter(Dummy.class, new InterfaceAdapter()).create();
Dummy d = new Dummy();
String json = gson.toJson(d);
System.out.println(json);
}
}

How to iterate through an Json array with same keys, but different values using Faster xml

I am trying to parse the json array with same key value which looks something like:
Back End Response:"Countries":[{"state":"Queens Land "state":"Tasmania"}].
2.I have created classes to read back end response and mapping the values with faster XML, but only the last value in the array is getting copied, instead of entire array. This is how I created my Data Transfer Object classes.
Now the Test object contains Countries array, but only one of the State value is read. i.e
"Countries":["States":"Tasmania"].
Please excuse me for typos. can some one help, can some one suggest whats wrong with the bellow code..
private Class Test{
List<Countries> countries;
}
private class Countries{
private String States;
}
private class Mapper {
}
In my Mapper class reading the value using faster XML
Assume that your JSON payload is:
{
"Countries": [
{
"state": "Queens Land",
"state": "Tasmania"
}
]
}
According to RFC7159:
An object structure is represented as a pair of curly brackets
surrounding zero or more name/value pairs (or members). A name is a
string. A single colon comes after each name, separating the name
from the value. A single comma separates a value from a following
name. The names within an object SHOULD be unique.
In your example, you have not unique names and most JSON parsers would skip repeated values and would take only one. So, if you can change backend response, just change it to:
{
"Countries": [
{
"state": "Queens Land"
},
{
"state": "Tasmania"
}
]
}
or
{
"Countries": [
"Queens Land",
"Tasmania"
]
}
But if you can not do that, you need to use Streaming API and implement your custom deserialiser. See below example:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class JsonPathApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
Test test = mapper.readValue(jsonFile, Test.class);
System.out.println(test);
}
}
class CountriesJsonDeserializer extends JsonDeserializer<Countries> {
#Override
public Countries deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
List<String> states = new ArrayList<>();
while (p.nextToken() != JsonToken.END_OBJECT) {
if (p.currentToken() == JsonToken.FIELD_NAME) {
if ("state".equalsIgnoreCase(p.getText())) {
p.nextToken();
states.add(p.getText());
}
}
}
Countries countries = new Countries();
countries.setStates(states);
return countries;
}
}
class Test {
#JsonProperty("Countries")
private List<Countries> countries;
public List<Countries> getCountries() {
return countries;
}
public void setCountries(List<Countries> countries) {
this.countries = countries;
}
#Override
public String toString() {
return "Test{" +
"countries=" + countries +
'}';
}
}
#JsonDeserialize(using = CountriesJsonDeserializer.class)
class Countries {
private List<String> states;
public List<String> getStates() {
return states;
}
public void setStates(List<String> states) {
this.states = states;
}
#Override
public String toString() {
return "Countries{" +
"states=" + states +
'}';
}
}
Above example prints:
Test{countries=[Countries{states=[Queens Land, Tasmania]}]}
See also:
Intro to the Jackson ObjectMapper

How to parse a Java List of already parsed JSON into a Big JSON?

I use Jackson to serialize/deserialize JSON.
I have a List<String> in which all elements inside are already serialized in JSON format. I would like to generate a big JSON from that List.
In other word, I have:
List<String> a = new ArrayList<>();
a[0] = JSON_0
a[1] = JSON_1
...
a[N] = JSON_N
And I would like to render:
[
{JSON_0},
{JSON_1},
...
{JSON_N}
]
What is the best way to do so using Jackson?
Probably the simpler solution would be to create ArrayNode and use addRawValue method:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.util.RawValue;
public class JsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ArrayNode nodes = mapper.getNodeFactory().arrayNode();
nodes.addRawValue(new RawValue("{}"));
nodes.addRawValue(new RawValue("true"));
nodes.addRawValue(new RawValue("{\"id\":1}"));
System.out.println(mapper.writeValueAsString(nodes));
}
}
Above code prints:
[{},true,{"id":1}]
You can also, create a POJO with list and use #JsonRawValue annotation. But if you can not have extra root object you need to implement custom serialiser for it. Example with POJO and custom serialiser:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class JsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
List<String> jsons = new ArrayList<>();
jsons.add("{}");
jsons.add("true");
jsons.add("{\"id\":1}");
RawJsons root = new RawJsons();
root.setJsons(jsons);
System.out.println(mapper.writeValueAsString(root));
}
}
#JsonSerialize(using = RawJsonSerializer.class)
class RawJsons {
private List<String> jsons;
public List<String> getJsons() {
return jsons;
}
public void setJsons(List<String> jsons) {
this.jsons = jsons;
}
}
class RawJsonSerializer extends JsonSerializer<RawJsons> {
#Override
public void serialize(RawJsons value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartArray();
if (value != null && value.getJsons() != null) {
for (String json : value.getJsons()) {
gen.writeRawValue(json);
}
}
gen.writeEndArray();
}
}
If you need to have SerializationFeature.INDENT_OUTPUT feature enabled for all items in array, you need to deserialise all inner objects and serialise them again.
See also:
How can I include raw JSON in an object using Jackson?
Handling raw JSON values using Jackson
the simple fact of having the character '[' we are marking that it is an array so what I recommend to put the list into a JSON array.
I would need a little more information to help you, since it doesn't make much sense to use a JSON String, since a JSON is composed of Key / Value, it is best to make a bean / object with the attribute.
Example:
class Object {
private String attribute = value;
}
{attribute: value}

Having issue collecting Json object and array with java

First of all, i am new to this so please pardon me. Have been working on a music app and I am trying to parse JSON code from a streaming link and display "artist" name and "title" of song to my app users. But i am having issues collecting the data.
Here is my JSON code from the streaming link:
{"type":"result","data":[{"title":"My Stream ","song":"Unknown - The Authorised One","track":{"artist":"Unknown Artist","title":"The Authorised One","album":"Unknown","royaltytrackid":181938.0000,"started":1498151105,"id":181938,"length":0,"playlist":{"id":3520,"title":"Rev Arome E. Adah"},"buyurl":"https:\/\/itunes.apple.com\/us\/album\/the-unknown-god\/id772022436?uo=4","imageurl":"http:\/\/is5.mzstatic.com\/image\/thumb\/Music5\/v4\/d7\/6d\/52\/d76d52df-db43-7130-0e37-62241ff50a21\/source\/100x100bb.jpg"},"bitrate":"128 Kbps","server":"Online","autodj":"Online","source":"Yes","offline":false,"summary":"<a href=\"http:\/\/cp9.serverse.com:2199\/tunein\/-stream\/svhxmwhp.pls\">Eloti Designs Stream - Unknown - The Authorised One<\/a>","listeners":0,"maxlisteners":1000,"reseller":0,"serverstate":true,"sourcestate":true,"sourceconn":1,"date":"Jun 22, 2017","time":"07:06 PM","rawmeta":"Unknown - The Authorised One ","mountpoint":"\/stream","tuneinurl":"http:\/\/209.133.216.3:7550\/stream","directtuneinurl":"","proxytuneinurl":"http:\/\/209.133.216.3\/proxy\/svhxmwhp?mp=\/stream","tuneinformat":"mp3","webplayer":"muses","servertype":"ShoutCast2","listenertotal":0,"url":"http:\/\/cp9.serverse.com:2199\/rpc"}]
I used this code to post "artist" name of "Unkwown Artist" to my text field but it didn't work for me.
JSONObject parentObject = new JSONObject(finalJson);
JSONArray parentArray = parentObject.getJSONArray("data");
JSONObject finalObject = parentArray.getJSONObject(0);
String songName = finalObject.getString("artist");
return songName;
track is a jsonobject containing artist and track is inside first jsonobject of
data array so fetch track then fetch artist from it
String songName = finalObject.getJSONObject("track").getString("artist");
{
"type":"result",
"data":[ // fetch JSONArray
{ // fetch first JSONObject
"title":"My Stream ","song":"Unknown - The Authorised One",
"track":{ // fetch track JSONObject
"artist":"Unknown .." // fetch string
Have you tried the jackson parser? It's super easy to use and can easily parse the string above. All you need to do is create 3/4 POJO classes that map your structure and then apply the readValue function of the Mapper to the outer class. Following is a small example with a List and one inner class:
import java.io.IOException;
import java.util.List;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
class OutterPojo {
public String aString;
public List<InnerPojo> aList;
public String getaString() {
return aString;
}
public void setaString(String aString) {
this.aString = aString;
}
public List<InnerPojo> getaList() {
return aList;
}
public void setaList(List<InnerPojo> aList) {
this.aList = aList;
}
#Override
public String toString() {
return new StringBuilder().append("{ #OutterPojo# ").append("aString:").append(aString).append(", ").append("aList:")
.append(aList).append(" }").toString();
}
}
class InnerPojo {
public String anotherString;
public String getanotherString() {
return anotherString;
}
public void setanotherString(String anotherString) {
this.anotherString = anotherString;
}
#Override
public String toString() {
return new StringBuilder().append("{ #InnerPojo# ").append("anotherString:").append(anotherString).append(" }")
.toString();
}
}
public class Test {
public static void main(String args[]) throws JsonParseException, JsonMappingException, IOException {
String jsonData = "{\"aString\":\"s\",\"aList\":[{\"anotherString\":\"ss\"},{\"anotherString\":\"sss\"}]}";
ObjectMapper objectMapper = new ObjectMapper();
OutterPojo testObject = objectMapper.readValue(jsonData, OutterPojo.class);
System.out.println(testObject);
}
}
As to dependencies all you need for this to work is jackson-core, jackson-databind and jackson-annotations - here's the link to maven:
https://mvnrepository.com/artifact/com.fasterxml.jackson.core
Hope it helps! :)

Array Json to List<MyObject> with Gson or Xtream

Hello I had this follow json code.
[{"check":{"domain":"qwe.coedu.br"}},{"check":{"domain":"qwe.com.br"}},{"check":{"domain":"qwe.com"}}]"
How do to convert this json in my object
class Check {String domain , String status ...}
It return a List<Check>, but the Check attributes are null. See my code. with Gson.
Gson gson = new Gson();
Type fooType = new TypeToken<Collection<Check>>(){}.getType();
System.out.println(((List<Check>)gson.fromJson("[{\"check\":{\"status\":\"2\",\"domain\":\"william.com.br\"}}]", fooType)).get(0).getDomain());
When I debug my returned list, this contains all objects in list, but all with your attributes null.
What is wrong ?
You need a customized converter, because you have a list of objects that holds a property named check. And this property is of a class that has the properties domain and status.
Two possibilities here:
if you don't want to change the Json format, or you simply can't probably write your own JsonDeserializer, in which you will instanciate your Check object and then set the properties by your own is the best choice;
or you could modify your check class in order to hold a check property of a type that holds a property named domain and another one status.
For the second case is pretty clear what needs to be done, but for the first case you could do something like:
import java.lang.reflect.Type;
import java.util.Collection;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
public class GsonTestClass {
static class MyDeserializer implements JsonDeserializer<Check> {
public Check deserialize(JsonElement arg0, Type arg1,
JsonDeserializationContext arg2) throws JsonParseException {
JsonObject jsonObject = arg0.getAsJsonObject().get("check").getAsJsonObject();
// this code could be improved with null checks and so on...
return new Check( //
jsonObject.get("domain").getAsString(), //
jsonObject.get("status").getAsString() //
);
}
}
public static void main(String args[]) {
Gson gson = new GsonBuilder().registerTypeAdapter(Check.class, new MyDeserializer()).create();
String json = "[{\"check\":{\"status\":\"2\",\"domain\":\"william.com.br\"}}]";
Type fooType = new TypeToken<Collection<Check>>() {}.getType();
System.out.println((gson.fromJson(json, fooType)));
}
static class Check {
private String domain;
private String status;
public Check() {
}
public Check(String domain, String status) {
super();
this.domain = domain;
this.status = status;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
#Override
public String toString() {
return "Check: " + domain + " - " + status;
}
}
}
Your Java class Check with its fields domain and status corresponds to
{"status":"2","domain":"william.com.br"}
in JSON, so a JSON "equivalent" of List<Check> would be
[{"status":"1","domain":"qwe.coedu.br"},{"status":"1","domain":"qwe.com.br"}]
Your JSON has another level of object nesting, where each list entry is an object with one property named check. Either restructure you JSON to remove the seemingly unnecessary nesting, or deserialize into e.g.
List<Map<String,Check>>

Categories

Resources