Converting enum of variable length values using jsonschema2pojo - java

I am trying to create a json schema for a corresponding Java enum of variable length values. Information follows :
JSON tried :
"Info": {
"type": "string",
"enum": [
"TITLE",
"ADDRESS",
"NAME";
]
}
But this wouldn't provide the desired output instead the converted java class I am getting is
Current Output :
public static enum Info {
TITLE("TITLE"),
ADDRESS("ADDRESS"),
NAME("NAME");
}
Required Java Output :
public enum Info {
TITLE(45),
ADDRESS(100),
NAME(45);
private Integer maxLength;
Info(Integer maxLength) {
this.maxLength = maxLength;
}
public Integer getMaxLength() {
return maxLength;
}
}
Unable to figure out a way to solve this. Would appreciate any help.

As far as I can tell this is currently not possible. If you look at the source code, then enums are generated by org.jsonschema2pojo.rules.enumRule. jsonschema2pojo provides a constructor to each enum which for your use case would need to take a single argument of type Integer. The constructor is generated in line 199 by the following code
JVar valueParam = constructor.param(String.class, VALUE_FIELD_NAME);
That is, the constructor is hard coded to always take a single argument of type String.
The best you can probably do is to use the javaEnumNames property which allows you to specify the names and values of your enums (with the restriction that the value is always a string).
{
"javaEnumNames" : [
"TITLE",
"ADDRESS",
"NAME"
],
"enum" : [ 45, 100, 45 ]
}
This JSON snippet produces
...
TITLE("45"),
ADDRESS("100"),
NAME("45");
...

Related

How do I convert a json field of nested arrays into a Java entity?

I have a json from the Twitter Stream API. A field in this json consists of a nested array.
This json field looks like this:
{
"bounding_box": {
"coordinates": [
[
[
-74.026675,
40.683935
],
[
-74.026675,
40.877483
],
[
-73.910408,
40.877483
],
[
-73.910408,
40.3935
]
]
],
"type": "Polygon"
}
}
I create a java class called BoundingBox, and in it I define a variable of the type coordinates. What type should this variable have?
I need help with how to turn this space into a Java object. Can you please help me?
Actually your coordinates property is three dimensional array so to parse it you would have to use for example List<List<List<Double>>>. Your BoundingBox class could look like this :
public class BoundingBox {
private List<List<List<Double>>> coordinates;
private String type;
// constructors, getters, setter
}
Personally I think that storing data in three nested lists is a bad approach and you should think how to logically arrange those data. Maybe the most nested list represent x, y coordinates of some location and you could create another POJO that would actually make your data model more readable.

Parsing JSON String Array of Arrays in Spring

I am trying to parse json string in spring using pojo classes. I've a json string as:
{
"values": [
[
1509836400000,
670042.375,
2
],
[
1509836400000,
670042.375,
2
]
]
}
Can somebody help me how do I parse this string to object of the form
class Value{
long timeStamp;
double value;
int flag;
// getters and setters
}
class Values{
Value[] values;
// getters and setters
}
use Gson library to parse Json to Java like this.
Gson gson = new Gson();
Values values = gson.fromJson(yourJsonString , Values.class);
you can convert Json to Java POJOs using this tool Json to Java
You can use jackson 2
Reference
you can use the jackson library which is able of converting the string object to the desired pojo class
so please check this example
https://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/
If you are able the change the json to meet your model/pojo
just convert it from array to object like this Json:
{
"values": [ {
"timeStamp" : 1509836400000,
"value" : 670042.375,
"flag" : 2
},
{
"timeStamp" : 1509836400000,
"value" : 670042.375,
"flag" : 2
} ]
}
If you aren't able to change the json, you can map the values as List<List<Double>>, and then get every one by index: 0 for timeStamp and so on. Your model/pojo should be:
class Values {
List<List<Double>> values;
// getters and setters
}

GSON How to deserialize to a class with this array json string

I am struggling to find a way to serialize / deserialize this JSON output to a Java class? Can anyone provide code sample?
[
{
"topic": "this is my topic"
},
[
{
"name": "John"
},
{
"age": 100
}
]
]
My current attempt uses this Javabean:
public class Test {
private String topic;
private List<Person> listOfPersons;
}
Which I try to deserialize data into using Gson:
gson.fromJson(this.json, Test[].class);
But the deserialization fails, because Gson is looking for a list of persons in the JSON, but it doesn't exist.
It doesn't seem like having an object next to an array, inside an array, is sensical. It would make sense to put things this way:
{
"topic": "this is my topic",
"listOfPersons" : [
{
"name": "John",
"age": 100
},
{
... another person
}
]
}
Then you could just have a Person class:
public class Person {
private String name;
private int age;
}
...and you could deserialize with the code you already have.
The problem here is that your JSON data is syntactically correct, but semantically ambiguous. And by that I mean, it appears to represent a polymorphic array, where each item in the array is of a different type.
In addition, the portion representing a 'person' seems to have been de-normalized horribly, where each attribute of a person is represented as a separate object in an array. Quite weird indeed. Unfortunately its really impossible to tell what types are represented just by looking at the data alone, and there are no hints provided to allow Gson to deserialize the data for you. The best you can do in this case is manually parse the information.
Test test = new Test();
JsonArray rootArray = new JsonParser().parse(jsonString);
test.setTopic(rootArray.get(0).get("topic");
Person person = new Person();
JsonArray personArray = rootArray.get(1);
person.setName(personArray.get(0).get("name"));
person.setAge(personArray.get(1).get("age"));
test.setListOfPersons(Arrays.asList(person));

How to force Java JSON or GSON to explicitly name my arrays and objects

I have the following POJO:
public class Widget {
private String fizz;
private String buzz;
private String foo;
// Getters and setters for all 3...
}
In my code, I am trying to convert a List<List<Widget>> into JSON using the Java JSON library (however I'd also accept any answer using GSON as well).
Here is my code:
// Returns a single List<Widget> with 2 Widgets in it...
List<List<Widget>> widgetGroups = getWidgetGroups();
String widgetGroupsAsJson = JSON.encode(widgetGroups);
System.out.println(widgetGroupsAsJson);
This prints:
[
[
{
"fizz": "Yes",
"buzz": "Never",
"foo": "Always"
},
{
"fizz": "Sometimes",
"buzz": "Always",
"foo": "Pending"
}
]
]
Whereas I want the JSON to appear as:
"widgetGroups": [
"widgetGroup": [
"widget": {
"fizz": "Yes",
"buzz": "Never",
"foo": "Always"
},
"widget": {
"fizz": "Sometimes",
"buzz": "Always",
"foo": "Pending"
}
]
]
In other words, I want all the lists, as well as each widget, to be "named". My first concern, however, is that this may not be proper JSON. When I paste this 2nd (desired) JSON snippet into jsonlint.org I get a parser error.
So first I'm asking if someone could be so kind as to point out what my desired JSON should look like in order to be proper; and then second if someone could help me massage my widgetGroups list so that either Java JSON or GSON can produce the desired output. Thanks in advance!
First, are you sure this is correct? The comment and code does not match .
// Returns a single List<Widget> with 2 Widgets in it...
List<List<Widget>> widgetGroups = getWidgetGroups();
Second, create a WidgetGroup class that will act as a container for a single WidgetGroup.
public class WidgetGroup {
private String name;
private List<Widget> widgets;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Widget> getWidgets() {
return widgets;
}
public void setWidgets(List<Widget> widgets) {
this.widgets = widgets;
}
}
This would be a valid JSON structure:
{
"widgetGroups" : [
{
"widgetGroup": [
"widget": {
"fizz": "Yes",
"buzz": "Never",
"foo": "Always"
},
/*More widgets*/
]
},
/*More widget groups*/
]
}
Something like this should work:
Map<String, List<WidgetGroup>> widgetGroups = new HashMap<String, List<WidgetGroup>>();
WidgetGroup widgetGroup1 = getWidgetGroup(); // Just an assumption of one of your methods.
WidgetGroup widgetGroup2 = getWidgetGroup(); // Just an assumption of one of your methods.
List<WidgetGroup> widgetGroupList = new ArrayList<WidgetGroup>();
widgetGroupList.add(widgetGroup1);
widgetGroupList.add(widgetGroup2);
widgetGroups.put("widgetGroups", widgetGroupList);
Then you call toJson() on the map.
In JSON there are only two types of "containers" - arrays, which are implicitly ordered but not named, and object (or associative arrays), which are not necessarily ordered but have named key-value pairs. The correct JSON syntax should be:
{
"widgetGroups": [
{
"widgetGroup": [
{
"fizz": "Yes",
"buzz": "Never",
"foo": "Always"
},
{
"fizz": "Sometimes",
"buzz": "Always",
"foo": "Pending"
}
]
}
]
}
You should note that inside the "widgetGroup" list i placed an array - you either must give up names and put up a simple array ([] syntax), or an object ({} syntax) and use unique names (i.e. you can't have two identical elements named "widget")
As for the syntax to get this from GSON (or other common java-json transformers) use maps instead of lists where you want an associative array.
Edit: I've not worked previously with JSON-Java but looking at the specs it seems you need the JSONObject class to insert associative arrays.

Configure XStream to dynamically map to different objects

I am hitting a RESTful 3rd party API that always sends JSON in the following format:
{
"response": {
...
}
}
Where ... is the response object that needs to be mapped back to a Java POJO. For instance, sometimes the JSON will contain data that should be mapped back to a Fruit POJO:
{
"response": {
"type": "orange",
"shape": "round"
}
}
...and sometimes the JSON will contain data that should be mapped back to an Employee POJO:
{
"response": {
"name": "John Smith",
"employee_ID": "12345",
"isSupervisor": "true",
"jobTitle": "Chief Burninator"
}
}
So depending on the RESTful API call, we need these two JSON results mapped back to one of the two:
public class Fruit {
private String type;
private String shape;
// Getters & setters for all properties
}
public class Employee {
private String name;
private Integer employeeId;
private Boolean isSupervisor;
private String jobTitle;
// Getters & setters for all properties
}
Unfortunately, I cannot change the fact that this 3rd party REST service always sends back a { "response": { ... } } JSON result. But I still need a way to configure a mapper to dynamically map such a response back to either a Fruit or an Employee.
First, I tried Jackson with limited success, but it wasn't as configurable as I wanted it to be. So now I am trying to use XStream with its JettisonMappedXmlDriver for mapping JSON back to POJOs. Here's the prototype code I have:
public static void main(String[] args) {
XStream xs = new XStream(new JettisonMappedXmlDriver());
xs.alias("response", Fruit.class);
xs.alias("response", Employee.class);
// When XStream sees "employee_ID" in the JSON, replace it with
// "employeeID" to match the field on the POJO.
xs.aliasField("employeeID", Employee.class, "employee_ID");
// Hits 3rd party RESTful API and returns the "*fruit version*" of the JSON.
String json = externalService.getFruit();
Fruit fruit = (Fruit)xs.fromXML(json);
}
Unfortunately when I run this I get an exception, because I have xs.alias("response", ...) mapping response to 2 different Java objects:
Caused by: com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$UnknownFieldException: No such field me.myorg.myapp.domain.Employee.type
---- Debugging information ----
field : type
class : me.myorg.myapp.domain.Employee
required-type : me.myorg.myapp.domain.Employee
converter-type : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
path : /response/type
line number : -1
version : null
-------------------------------
So I ask: what can I do to circumvent the fact that the API will always send back the same "wrapper" response JSON object? The only thing I can think of is first doing a String-replace like so:
String json = externalService.getFruit();
json = json.replaceAll("response", "fruit");
...
But this seems like an ugly hack. Does XStream (or another mapping framework) provide anything that would help me out in this particular case? Thansk in advance.
There are two ways with Jackson:
test manually that the wanted keys are there (JsonNode has the necessary methods);
use JSON Schema; there is one API in Java: json-schema-validator (yes, that is mine), which uses Jackson.
Write a schema matching your first object type:
{
"type": "object",
"properties": {
"type": {
"type": "string",
"required": true
},
"shape": {
"type": "string",
"required": true
}
},
"additionalProperties": false
}
Load this as a schema, validate your input against it: if it validates, you know you need to deserialize against your fruit class. Otherwise, make the schema for the second item type, validate against it as a security measure, and deserialize using the other class.
There are code examples for the API, too (version 1.4.x)
If you do know the actual type, it should be relatively straight-forward with Jackson.
You need to use a generic wrapper type like:
public class Wrapper<T> {
public T response;
}
and then the only trick is to construct type object to let Jackson know what T there is.
If it is statically available, you just do:
Wrapper<Fruit> wrapped = mapper.readValue(input, new TypeReference<Wrapper<Fruit>>() { });
Fruit fruit = wrapped.response;
but if it is more dynamically generated, something like:
Class<?> rawType = ... ; // determined using whatever logic is needed
JavaType actualType = mapper.getTypeFactory().constructGenericType(Wrapper.class, rawType);
Wrapper<?> wrapper = mapper.readValue(input, actualType);
Object value = wrapper.response;
but either way it "should just work". Note that in latter case you may be able to use base types ("? extends MyBaseType"), but in general dynamic type can't be specified.

Categories

Resources