Generating JSON from java file - java

Is there a standard or existing way to generate 'something' from an uncompiled java class based on its contents? So basically something like this:
#MakeJsonDocumentation
public class ExistingClass{
private name = "";
public ExistingClass(String name){
this.name = name;
}
#JsonField
public String getName(){
return this.name;
}
#JsonField
public void setName(String name){
this.name = name;
}
#JsonMethod
public void someMethod(String text){
System.out.println("someMethod " + text)
}
#JsonMethod
public void otherMethod(){
System.out.println("otherMethod")
}
}
into something like this
{
"ExistingClass": {
"Fields": {
"Name": "String"
},
"Methods": {
"someMethod": {
"Parameters": {
"Type": "String",
"Name": "text"
},
"Returns": "Nothing"
},
"otherMethod": {
"Parameters": "Nothing",
"Returns": {
"Type": "String"
}
}
}
}
}
And if there isn't, is it possible to do this with compile-time annotations because I'd like to automate the generation instead of having to write a parser and everytime I change something about a class throw it through the parser in order to get an up-to-date datasheet.
I'm kind of in the dark here, I only know what I want but no idea how to accomplish it, so at very least some search-keywords into the right direction would be very welcome :p

To achieve Json you posted above you can by:
use reflection to extract all fields names and methods
use JSONObject (json parser/builder)
from an uncompiled java class
However, reflection works with instances (or all fields/methods must be static)

How about this?
https://jersey.java.net/documentation/1.17/json.html
Here's an older post that might help as well: Json - Java Object to Json
Cheers
.t.

Related

Deserialization with JSON objects which fields can be of different types

I have the following json file:
{
"authors":
[{"id":"author7",
"book":[
[
{
"value":{"pages":123}}]]},
{
"id": "author3",
"book": [
[
{
"value": {
"title": "LOTR"
}
},
{
"value": {
"boolean": false
}
},
],
[
{
"value": {
"pages": 350
}
},
{
"value": {
"boolean": false
}
},
],
[
{
"value": {
"boolean": false
}
},
{
"value": {
"pages": 150
}
},
]
]
},
}
I want to be able to create an object of Author but I am having problems while mapping the Json file with the Java classes I have created.
I understand that, while mapping the json file with the java classes, Authors class should have as fields
public class Authors{
private String authorId;
private Book book;
}
Class Book should be like this
public class Book {
private List<Values> values
public Book() {
}
}
But what about class Values?
public class Values{
private int pages;
private Boolean bool;
private String title;
public Values() {
}
}
Is this the correct way to map it? Because I see that if I create an object of Values it will ask me to modify the constructor or create a new constructor for each different object that comes from Json
Thank you for reading and helping!
Easy way out would to be to define Values by type 'object' as,
public class Book {
private List<Object> values
}
This way you won't run into the issue of having properties with null values when they don't exist in the JSON. Also, the JSON would be entirely parsed into an object even if new properties are get introduced (or which may not be defined under values class, as you have done above causing those not being mapped to the object).
However, when you are using 'object', be mindful with your logic that uses this parsed object. Although, you are assured to access the properties from the object as in the JSON, you will have to conditionally check whether the nessacary property exists first in each logical context to avoid possible undefined value errors.

Deserialization of JSON array

I'm not sure how to deserialize array containing plain strings.I'm trying to parse the following JSON
{
"state":"RT",
"testMethod":"electronic",
"testElements":[
{
"testId":[
"UT_ITXref",
"Fed_ITXref"
]
},
"testStartDate",
"testEndDate",
"testDueDate"
]
}
I'm getting the following error:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.test.rules.model.TestElements: no String-argument constructor/factory method to deserialize from String value ('testStartDate')
at [Source: {"state":"RT","testMethod":"electronic","testElements":[{"testId":["UT_ITXref","Fed_ITXref"]},"testStartDate","testEndDate","testDueDate"}]}; line: 1, column: 247] (through reference chain: com.test.rules.model.TestRules["testElements"]->java.lang.Object[][1])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:270)
at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1456)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1012)
at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:370)
at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:315)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1282)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:159)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:150)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:196)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:20)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:511)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:396)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1198)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:314)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:148)
at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1626)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1220)
Here is what I did , I used #JsonCreator annotation to deserialize
public class TestRules {
private String state;
private String testMethod;
private TestElements[] testElements;
#JsonCreator
public TaxRules(
#JsonProperty("state") String state,
#JsonProperty("testMethod") String testMethod,
#JsonProperty("testElements") TestElements[] testElements
) {
this.state = state;
this.testMethod = testMethod;
this.testElements = testElements;
}
}
public class TestElements {
private List<String> testId;
private List<String> elements;
public List<String> getElements() {
return elements;
}
public void setElements(List<String> elements) {
this.elements = elements;
}
public List<String> getTestId() {
return testId;
}
public void setTestId(List<String> testId) {
this.testId = testId;
}
}
Should I write custom deserializer or Is there any way that I can use the jackson API for this. Any suggestions would be appreciated.
Actually errors tells something.
JSON parser found that for testElements property there is an Array of Objects, but your Json file has mixed content.
first element is an object (I assume it is TestElement class). Then parser creates that object with empty constructor and calls appropriate setters for its properties.
but...
second,third and forth elements are String, so error says that parser tries to find constrictor with String as argument.
So, you may try to make that constructor in TestElement class and see will it work or not...
Do not forget to keep empty constructor as well.
I cannot guarantee it will work but, at least error says that.
BTW are you sure your Json object is correct? but not something like that?
{
"state":"RT",
"testMethod":"electronic",
"testElements":[
{
"testId":[
"UT_ITXref",
"Fed_ITXref"
]
}],
"testStartDate":"01-01-2017",
"testEndDate":"01-02-2017",
"testDueDate":"01-03-2017"
}
I'm a little confused because StartDate, EndDate, DueDate semantically look more like test attributes, not as elements in testElements array
{
"state": "RT",
"testMethod": "electronic",
"testElements": [
{
"testId": [
"UT_ITXref", // <-- this object is deserialized just fine
"Fed_ITXref"
]
},
"testStartDate", // <-- this is where the error is happening
"testEndDate",
"testDueDate"
]
}
Did you intend the json to be interpreted as if it looked like the following?
{
"state": "RT",
"testMethod": "electronic",
"testElements": [
{
"testId": [
"UT_ITXref",
"Fed_ITXref"
]
},
{
testId: [
"testStartDate"
]
},
{
testId: [
"testEndDate"
]
},
{
testId: [
"testDueDate"
]
}
]
}
If so, you'll need to make a custom deserializer to detect whether the element in the array is an object or a string. If it's a string, you'll probably want to construct the TestElement yourself.

How to Parse Nested / Multiple Json Objects using Retrofit

The JSON I'm parsing looks like this:
{ "version": 1
"data": {
"1001": {
"id": 1001,
"name": "herp",
"into": [
"3111": "we"
]
},
"1032": {
"id": 1002,
"name": "derp",
"into": [
"36": "w",
"12341: "c"
],
"tags": [
"hi there"
],
"cost" {
"even": 15
}
},
"1603": {
"id": 1003,
"name": "her",
"into": [
"37": "dll",
"58": "eow",
"32145": "3a"
],
"cost" {
"highest": 325
"lowest": 100
}
},
.... Even more data
}
The Json that is within "data" goes on for a while and does not have a set endpoint. I have no control over the Json, I'm just trying to read it. Unfortunately, with my class code I'm unable to get it to work. When I make a retrofit call the information inside "data" is empty.
I've tried many iterations of implementing this, including using a deserializer and restructuring my POJO code. This is the current state of my Data class:
public class Data {
private Map<String, Item> itemData;
// Relevant Getters, Setters and Constructors //
}
For my Item Class, the main issue is that the JSON Content isn't set, it can vary at times. As you can see above the values inside "into" vary and sometimes the amount of things within item changes as well such as "tags" or "cost":
public class Item {
private int id;
private String name;
private String group;
private String description;
private Map<String, String> into;
private List<String> tags;
private Map<String, Integer> cost;
// Relevant Getters, Setters and Constructors //
When I use this code my data class is empty, I don't see any errors in the log so I can't seem to figure out why the GSON isn't working with this.
In case you wanted to see how I construct my RestClient, here it is:
RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(ROOT)
.setClient(new OkClient(new OkHttpClient()))
.setLogLevel(RestAdapter.LogLevel.FULL);
RestAdapter restAdapter = builder.build();
REST_CLIENT = restAdapter.create(DataApi.class);
I know that my Rest Query works because I can get the content within "version" but everything inside data is null.
I am officially a dumb scrub and completely looked over the easiest possible fix and should have my account and developer title revoked.
This is all I should have done:
public class ItemGroup {
private String version;
private Map<String,Item> data;
//...Man i'm so dumb...
}
AS REFERENCE FOR THE FUTURE. The reason why this works is because the JSON is in this format { { } { } { } }. Which means you have 3 objects of objects, as opposed to { [ ] [ ] [ ] } which is 3 objects of a list. What I had done was treat { { } { } { } } as { { { } { } { } } }. Which is not correct. By using a map which is basically a collection of pairs, we are able to imitate the { { } { } { } } with a Map.
Map Object { {Key-Pair Object} {Key-Pair Object} {Key-Pair Object} }
Just a quick idea for your Pojos:
Not sure if this will work. Maybe write a custom deserializer.
public class YourResponse {
int version;
Data data;
class Data {
Subdata subData;
}
class Subdata {
private int id;
private String name;
private ArrayList<Into> into;
private ArrayList<String> tags;
//...
}
class Into {
// "3111": "we"
private String into;
}
}

Convert JSON with integers to Java POJO objects

I have this JSON data, and I was wondering how I might convert this data to a Java POJO object:
"progression": {
"64693": [
{
"1": 1
}
],
"64717": [
{
"1": 4
}
]
},
I was thinking it can't be:
public class Progression{
private List<64693> 64693;
private List<64717> 64717;
public List<64693> get64693(){
return this.64693;
}
public void set64693(List<64693> 64693){
this.64693 = 64693;
}
public List<64717> get64717(){
return this.64717;
}
public void set64717(List<64717> 64717){
this.64717 = 64717;
}
}
I'm very familiar with Java, so I know I can do a #JsonProperty instead of the actual numbers, but just wondering if there were any other choices.
Thanks!
_ug had the right suggestion:
... object consider naming 64693 to like DataType64693 and adding the
#JsonProperty("64693") annotation
That worked fine. And BTW, I am using the Jackson 2.0 JSON processor.

What is the data structure of this JSON?

I'm trying to parse Json to Java by using Gson, but when I use fromJson(), I always get null. Who can explain this data structure for me? Thanks!
{
"d": {
"results": [
{
"__metadata": {
"uri": "https://api.datamarket.azure.com/Data.ashx/Bing/SearchWeb/v1/Web?Query='bill'gates'&$skip=0&$top=1",
"type": "WebResult"
},
"ID": "9bd0942f-fe5b-44fc-8343-ef85e5b93a7e",
"Title": "The Official Site of Bill Gates - The Gates Notes",
"Description": "In the space between business and goverment, even a small investment can make a big impact on the lives of those in need.",
"DisplayUrl": "www.thegatesnotes.com",
"Url": "http://www.thegatesnotes.com/"
},
{
"__metadata": {
"uri": "https://api.datamarket.azure.com/Data.ashx/Bing/SearchWeb/v1/Web?Query='bill'gates'&$skip=1&$top=1",
"type": "WebResult"
},
"ID": "fdf0d3b9-b29f-43ef-b5ba-6bb4b1b04458",
"Title": "Bill Gates - Wikipedia, the free encyclopedia",
"Description": "William Henry \"Bill\" Gates III (born October 28, 1955) is an American business magnate and philanthropist. Gates is the former chief executive and current chairman of ...",
"DisplayUrl": "en.wikipedia.org/wiki/Bill_Gates",
"Url": "http://en.wikipedia.org/wiki/Bill_Gates"
}
],
"__next": "https://api.datamarket.azure.com/Data.ashx/Bing/SearchWeb/v1/Web?Query='bill'gates'&$skip=10&$top=10"
}
}
I think the data structure should be like this, but it doesn't work.
public class d {
public result[] results;
public String __next;}
public class result {
public information[] infolist;}
public class information {
public __metadata metadata;
public String ID;
public String Title;
public String Description;
public String DisplayUrl;
public String Url;}
public class __metadata {
public String uri;
public String type;}
Your Information class is the problem. Put the Information stuff into Result and remove the infolist from Result. Also, the field name for the meta data is __metadata. This isn't the class name. Lastly, you're missing a class to wrap d as a field.
public class DataContainer {
public Data d;
}
public class Data {
public Result[] results;
public String __next;
}
public class Result {
public Metadata __metadata;
public String ID;
public String Title;
public String Description;
public String DisplayUrl;
public String Url;
}
public class Metadata {
public String uri;
public String type;
}
You really should use common convention for class names. Gson won't preclude you from using your own names for classes. It only requires control for the name of the fields.
To deserialize:
String json = ... ;
DataContainer myDataContainer = new Gson().fromJson(JSONString , DataContainer.class);
Result[] myResult = myDataContainer.d.results;
Try that and see if that works.
Here's how you should interpret the JSON when you're writing a class structure around it for Gson:
An opening { indicates an object, so this will be a new class (or an existing one if they have the same fields)
A "this": indicates a field for the object it's inside, and the field must be named the same thing as the text in the string.
An opening [ indicates an array, a List, or a Set (Result[] results could just as easily be List<Result> results)

Categories

Resources