I have a need to parse some json that comes to an endpoint of mine. I cannot change the incoming json, it is sent by a 3rd party. The json in the request body is technically valid but it has no parent element so I can't seem to parse it. Ideally I'd be able to wrap the whole thing in an object, so basically, how can I actually add the "wrapper" object:
{
"wrapper": {
{
"value1": 1,
"value2": 2,
"value3": 3
}
}
}
if the original was:
{
"value1": 1,
"value2": 2,
"value3": 3
}
With that I could make a model and use xml annotation as I have elsewhere in the project, something like this:
#XmlRootElement(name = "wrapper")
#XmlAccessorType(XmlAccessType.NONE)
public class WrapperObject {
#XmlElement(name = "value1")
private int value1;
#XmlElement(name = "value2")
private int value2;
#XmlElement(name = "value3")
private int value3;
}
And then I could have the rest method be
#POST
#Path("/cloud")
#Override
public Response handleResponse(WrapperObject wrapper) throws Exception {
}
As your question is an answer, my answer will be a question. What do you ask? p.s. your idea and code look fine. When a project is spread between Front end and Back end teams they should always have a CONTRACT about the data transfer objects so parsing is possible for the both sides.
Related
I have a requirement where i have to accept the list of objects.
The method in mutation class looks like this
#GraphQLMutation //1
public void ack(#GraphQLInputField List<PingEntity> pingEntityList) { //2
log.info("Handling ack calls.");
pingEntityRepository.savePingEntityList(pingEntityList);
}
PingEntity looks like this
#Data
//#Document(collection="pingdatastore")
#AllArgsConstructor
#NoArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class PingEntity {
private String id;
#JsonProperty("action")
private String action;
#JsonProperty("message")
private String message;
#JsonProperty("timestamp")
private Long timestamp;
#JsonProperty("transactionId")
private String transactionId;
#JsonProperty("type")
private Integer type;
private String imei;
}
my query looks like this
mutation ack {
ack(pingEntityList: [{action: "KEEP-ALIVE2", message: "Keep alive message at regular intervals", timestamp: 1462747047}]) {
id
}
}
I got the Error like this:
"data": null,
"errors": [
{
"validationErrorType": "SubSelectionNotAllowed",
"message": "Validation error of type SubSelectionNotAllowed: Sub selection not allowed on leaf type Boolean",
"locations": [
{
"line": 2,
"column": 3
}
],
"errorType": "ValidationError"
}
]
}
I tried giving different annotations. i am not able to solve this issue.. need help in this issue
Thanks in advance :)
The problem seems to be that your ack method returns void which gets mapped to boolean, for the lack of a better option. As boolean is a simple scalar, you can not select anything from it, and you're trying to select an id in the query.
If you'd change your ack method to return the saved List<PingEntity>, you'd get the behavior you wanted.
But... more importantly, what library are you using, as the annotations I see (#GraphQLInputField) in your code are not from graphql-java (as graphql-java itself provides no annotations), nor from any of the libraries I recognize.
It seems to be coming from a really old and never publically released version of graphql-spqr. If this is indeed the case, you absolutely need to update to the latest as the version you seem to be using was alpha quality at best.
I am having a JSON coming from response payload of rest API. below is structure of simplified JSON but the actual is much more complex.
{
"hardware": {
"cores": 2,
"cpu": 1,
},
"name": "machine11",
"network": [
{
"interface_name": "intf1",
"interface_ip": "1.1.1.1",
"interface_mac": "aa : aa: aa: aa: aa"
}
]
}
Now I have to write POJO class to bind the JSON structure using JAXB annotations (javax.xml.bind.annotation.*).
Can anyone help me how to write POJO class for a complex JSON structure,converting JSON to XML and then using XML schema to generate class is not helping out is there any other way?
Thanks in advance:-)
As per the above JSON structure, your Java objects will look like this:
public class OutermostClass{
private Hardware hardware;
private String name;
private Set<Network> network = new HashSet<Network>;
}
public class Hardware {
private int cores;
private int cpu;
}
public class Network {
private String interface_name;
private String interface_ip;
private String interface_mac
}
I'm using Gson to parse responses from a server on Android. Each response has some useless (to me) data on it that complicates my Gson models. Here is the general hierarchy of json returned:
response: {
date: 1406253006807,
otherUselessData1: "This is some useless data",
otherUselessData2: "This is some useless data",
usefulJsonObject: { <---- This is really the object that I care about
}
}
Everything above or at the same level as usefulJsonObject I could really do without. The useless data is returned for every request, and the actual response is embedded beneath as the usefulJsonObject. This wouldn't be a big problem but it's really cluttering up my gson model objects.
For example:
Let's say I have 3 requests I can make: A, B, and C. For each response it seems I need to make a minimum of 3 custom classes.
public class ResponseA {
#SerializedName("response") ResponseObjectA responseObject;
public static class ResponseObjectA {
#SerializedName("usefulJsonObject") UsefulObjectA usefulObject;
}
public static class UsefulObjectA {
}
}
I've tried a few solutions, but I haven't found anything elegant that wouldn't add an extra step to my process. I'm using retrofit to do my http requests and it's really nice that it just returns the fully parsed gson object to me. I've thought of other solutions like having the useful object just be a JsonElement and then doing a 2nd gson call after the first comes back. Again, not ideal.
I just wanted to know if I was missing something. Surely I'm not the only one who's encountered something like this, and so I thought I'd ask how other people would handle something like this.
It is initialization Instance value, not NULL value. Check my example.
Address.java
public class Address {
public Address(){
}
}
Person.java
public class Person {
private String name;
private String nrc;
private Address address;
public Person(String name, String nrc, Address address) {
this.name = name;
this.nrc = nrc;
this.address = address;
}
}
The following Json string is equalvent to
Person person = new Person("Zaw Than Oo", "11111", null);
{
"name": "Zaw Than Oo",
"nrc": "11111"
}
The following Json string is equalvent to
Person person = new Person("Zaw Than Oo", "11111", new Address());
{
"name": "Zaw Than Oo",
"nrc": "11111",
"address": {} <-- here use less object for you.
}
Even if you don't create new Instance, Other lib/api(you used) may be create that instance by Reflection.
Short to the Point
{
...
"xxx": {} --> new instance without data/value
...
}
{
...
--> null value
...
}
I never found an elegant way dealing with just Gson. I tried several options with Generics, all of which didn't work or left something to be desired.
Since I'm using Retrofit, I decided to override the GsonConverter, and just filter out the unnecessary information from all my requests. It ends up not being as flexible, as in I can't use the same Retrofit network interface for calls to other servers, but I'm not really doing that, and it also has the down side of having 2 rounds of json parsing calls (meh). You could probably do this more efficiently, but this is working for me for now.
public class CustomGsonConverter extends GsonConverter {
private Gson mGson;
public CustomGsonConverter(Gson gson) {
super(gson);
this.mGson = gson;
}
public CustomGsonConverter(Gson gson, String encoding) {
super(gson, encoding);
this.mGson = gson;
}
#Override public Object fromBody(TypedInput body, Type type) throws ConversionException {
try {
CustomResponse customResponse = mGson.fromJson(new InputStreamReader(body.in()), CustomResponse.class);
return mGson.fromJson(customResponse.responseObject.data, type);
} catch (IOException e) {
throw new ConversionException(e);
}
}
public static class CustomResponse {
#SerializedName("rsp") ResponseObject responseObject;
public static class ResponseObject {
// #SerializedName("date") long date;
#SerializedName("data") JsonElement data;
}
}
}
Maybe there is a better way that I'm just not realizing.
I was given json file and third party class:Dealer and interface IDealerAttributes (I can not change either of them);
(I remove package name and imports to make the code simple)
JSON file
{
"serviceURL": "com.mycompany.serviceURL",
"dealerAttributes": [
{
"language": "language0",
"dealerAttributeName": "dealerAttributeName0",
"updateDate": 0
},
{
"language": "language1",
"dealerAttributeName": "dealerAttributeName1",
"updateDate": 1
}
]
}
class Dealer {
private String serviceURL;
private List dealerAttributes;
public Dealer() {
dealerAttributes = new ArrayList();
}
//Getters and Setters...
}
public interface IDealerAttributes {
public String getLanguage();
public String getDealerAttributeName();
public long getUpdateDate();
}
once I use:
gson.fromJson(jsonObj.toString(), Dealer.class);
I will get exception from this line:
Exception unmarshalling json String into Object: com.google.gson.JsonParseException: The JsonDeserializer com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter#60e26ffd failed to deserialize json object [{"language":"language0","dealerAttributeName":"dealerAttributeName0","updateDate":0},{"language":"language1","dealerAttributeName":"dealerAttributeName1","updateDate":1}] given the type java.util.List
How can I read this json file based on Dealer.class, IDealerAttributes?
But I can add one class, let's say:
public class DealerAttributes implements IDealerAttributes {
private String language;
private String dealerAttributeName;
private long updateDate;
public DealerAttributes() {
}
//Getters and Setters...
}
Since I am new to json/gson, would you please give detailed instruction to help me out? Thanks.
[added]
Consider if there are 100 fields in Dealer class, and there are another 100 interface used/nested in Dealer. I am thinking whether anyone have experience using this way: (MyType is interface)
gson.registerTypeAdapter(MyType.class, new MyType());`
You could map it to a List of Maps and then use a BeanMapper like http://code.google.com/p/orika/ to get some more informative error messages
HI!
I am working with a .json file, like this:
[{
"SourceFile": "videos/KobeAlleyOop.flv",
"ExifTool": {
"ExifToolVersion": 8.22,
"Warning": "Truncated 'mdat' data"
},
"System": {
"FileName": "KobeAlleyOop.flv",
"Directory": "videos",
"FileSize": "4.8 MB",
"FileModifyDate": "2010:06:15 14:57:24+02:00",
"FilePermissions": "rwxr-xr-x"
},
"File": {
"FileType": "MP4",
"MIMEType": "video/mp4"
}]
I made a Bean with 3 components:
public class MetadataContentBean {
SourceFileBean sourceFileBean;
FileBean fileBean;
SystemBean systemBean;
public FileBean getFileBean() { return fileBean; }
#JsonProperty("File")
public void setFileBean(FileBean fileBean) {
this.fileBean = fileBean; }
public SystemBean getSystemBean() {
return systemBean; }
#JsonProperty("System")
public void setSystemBean(SystemBean systemBean) {
this.systemBean = systemBean; }
public SourceFileBean
getSourceFileBean() {
sourceFileBean.getSource(); return
sourceFileBean; }
#JsonProperty("SourceFile")
public void setSourceFileBean(SourceFileBean
sourceFileBean) {
this.sourceFileBean = sourceFileBean;
} }
And I add an example of SourceFileBean, the others are similar:
public class SourceFileBean {
private String source;
public String getSource() {
return source;
}
#JsonProperty("SourceFile")
public void setSource(String source) {
this.source = source;
}
}
In the main program I make this call:
InputStream is = this.getClass().getClassLoader().getResourceAsStream(filename);
String jsonTxt = IOUtils.toString(is);
JSONArray json = (JSONArray) JSONSerializer.toJSON(jsonTxt);
JSONObject metadatacontent = json.getJSONObject(0);
ObjectMapper mapper = new ObjectMapper(); mapper.readValue(metadatacontent.toString(),MetadataContentBean.class);
But I get this error when I run it, I don't know why:
org.codehaus.jackson.map.JsonMappingException:
Can not construct instance of
com.path.bean.SourceFileBean,
problem: no suitable creator method
found at [Source:
java.io.StringReader#12d7a10; line: 1,
column: 2] at
org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:159)
at
org.codehaus.jackson.map.deser.StdDeserializationContext.instantiationException(StdDeserializationContext.java:212)
at
org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromString(BeanDeserializer.java:415)
at
org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:291)
at
org.codehaus.jackson.map.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:135)
at
org.codehaus.jackson.map.deser.SettableBeanProperty$MethodProperty.deserializeAndSet(SettableBeanProperty.java:221)
at
org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:390)
at
org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:286)
at
org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:1588)
at
org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1116)
at
com.path.parser.JSon.Parser(JSon.java:65)
at
com.path.parser.JSon.main(JSon.java:29)
Any help?? Thanks in advance!
I'm guessing that this is just because your JSON represents an array, with a single object inside it. You're asking Jackson to deserialize this array data onto a single instance of MetadataContentBean, which it can't do.
Try removing the [] brackets from around the JSOn, and try again.
The problem was about sintaxis and the way of writting the fields in my program.
You must be absotuely sure that it is the SAME as in the json file.
On the other hand
"SourceFile": "videos/KobeAlleyOop.flv"
is a field with just one field, so is not neccesary make a bean for it.
It is a stupid error which could make you waist a lot of time!!! :s
One problem is that you have unnecessary code in there: lines 3 and 4 are not needed and could cause issues. So just do:
InputStream is = this.getClass().getClassLoader().getResourceAsStream(filename);
String jsonTxt = IOUtils.toString(is);
ObjectMapper mapper = new ObjectMapper();
MetadataContentBean[] beans = mapper.readValue(metadatacontent.toString(),MetadataContentBean[].class);
so you don't have to use json.org's parser in there. This may not explain exact problem but helps avoid secondary issues.
But the specific problem that throws exception is simple(r): JSON value for type is String, but you are trying to make an Object (bean) out of it.
To make it work, add a public constructor that takes one String argument, and it should work.
You can annotate it with #JsonCreator if you want (or if it's not public constructor), but that should not be necessary.
Conversely, if you want to serialize a bean as JSON String, you need to do something like
#JsonValue public String asString() { return valueOfThisAsString; }