GeoJson Jackson - parse JSON to Java object fails - java

I am working on parsing a GeoJSON file into Java POJO classes.
I have found the GeoJSON Jackson library which seems to be exactly the same as I need.
https://github.com/opendatalab-de/geojson-jackson
I have a JSON like the following:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"lfdNr": 1,
"betriebsNummer": 33,
"nummer": 4,
"bezeichnung": "TERST",
"kng": 61062323,
"nArtCode": "A",
"nArtB": "ACKERLAND",
"flaeche": 4.0748
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
15.8867118536754,
48.4004384452486
],
[
15.884483831836,
48.3981983444393
],
[
15.8847389374202,
48.3991957290405
],
[
15.8853143451339,
48.3991585954555
],
[
15.8851662097189,
48.398462039698
],
....
]
]
}
}
]
}
I wish to use it as a FeatureCollection java object:
objectMapper.readValue(json, FeatureCollection.class);
I get the following:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct
instance of `org.geojson.GeoJsonObject`
(no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types,
have custom deserializer, or contain additional type information
at [Source: (String)"{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"lfdNr":1,"betriebsNummer":10086722,"nummer":4,"bezeichnung":"TERST","fskennung":61062323,"nutzungsArtCode":"A","nutzungsArtBezeichnung":"ACKERLAND","flaeche":4.0748},"geometry":{"type":"Polygon","coordinates":[[[15.8867118536754,48.4004384452486],[15.8829132747878,48.4002081767679],["[truncated 2362 chars]; line: 1, column: 251]
(through reference chain: org.geojson.FeatureCollection["features"]->java.util.ArrayList[0]->org.geojson.Feature["geometry"])
I assume it is because the class Geometry a generic type is:
public abstract class Geometry<T> extends GeoJsonObject
I only operate with Polygons and Points.
Any ides how can I get it working?
Thanks a lot!

You can read this JSON content by
GeoJsonObject object = objectMapper.readValue(json, GeoJsonObject.class);
if (object instanceof FeatureCollection) {
FeatureCollection featureCollection = (FeatureCollection) object;
...
}
Jackson will automatically recognize your JSON example as a FeatureCollection object,
because of the annotations on the GeoJsonObject class:
#JsonTypeInfo(property = "type", use = Id.NAME)
#JsonSubTypes({ #Type(Feature.class), ..., #Type(FeatureCollection.class), ... })
...
public abstract class GeoJsonObject implements Serializable {
...
}

Related

JSON-Simple. Modify and use complex object

I am using the JSON-simple library to parse the Json format. How can I use or modify something to a JSONArray? For e.g. consider the following json
"Place": [
{
"name": "owner 1"
},
{
"name": "owner 2"
}
],
"branch": [
{
"name": "sucursal",
"employe": [
],
"clients": [
]
},
I need to add some clients and in the future modify them. How to achieve this?
Simply create a pojo class in the same format.
Classs Pojo{
private List<Place> place;
private List<Branch> branch;
// other fields
}
and use writeValueAsString() from your object mapper to convet it to json.

How to pass a Map object to a RestController method?

I have an API method like below inside my RestController
#PostMapping("/asd")
public ResponseEntity<String> asd(#RequestBody MyParams params) { ... }
MyParams class is like below.
public class MyParams implements Serializable {
public List<Long> ids;
public List<String> ignoredTypes;
public Map<String, List<String>> aMapping;
}
In postman, I pass a JSON string like
{
"ids": [28712, 344248],
"ignoredTypes": [],
"aMapping": "{\"Person\":[\"name\",\"age\"],\"Title\":[\"start\",\"end\"]}",
}
I get an error saying
2021-08-16 18:25:53.953 WARN 4164 --- [io-8080-exec-10]
.w.s.m.s.DefaultHandlerExceptionResolver : Resolved
[org.springframework.http.converter.HttpMessageNotReadableException:
JSON parse error: Cannot construct instance of
java.util.LinkedHashMap (although at least one Creator exists): no
String-argument constructor/factory method to deserialize from String
value ('{"Person":["name","age"],"Title":["start","end"]}'); nested
exception is
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot
construct instance of java.util.LinkedHashMap (although at least one
Creator exists): no String-argument constructor/factory method to
deserialize from String value
('{"Person":["name","age"],"Title":["start","end"]}') at [Source:
(PushbackInputStream); line: 12, column: 20] (through reference chain:
com.xyz.MyParams["aMapping"])]
So basically java.util.Map cannot be parsed from JSON string. How can I do that?
Did you tried like this
{
"prop1": [1],
"prop2": ["string"],
"prop3": {
"additionalProp1": [
"string"
],
"additionalProp2": [
"string"
],
"additionalProp3": [
"string"
]
}
}
Try to pass the JSON object as it is without stringifying
I changed the request body and it worked.
{
"ids": [
28712,
344248
],
"ignoredTypes": [
],
"aMapping": {
"Person": [
"name",
"age"
],
"Title": [
"start",
"end"
]
}
}

Deserializing JSON with Jackson for polymorphic classes

I am attempting to deserialize JSON which can be either a GroupRule or AttributeRule:
AbstractRule
GroupRule
AttributeRule
I want my models/entities/POJOs to be generic as I also use the same classes in other projects with Snakeyaml or other serialization providers.
Having said that, I stumbled across this: https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization
which in the article, it indicates I could do:
{ // Using fully-qualified path
"#class" : "com.fasterxml.beans.EmployeeImpl", ...
}
However, when I do that, I am getting:
Cannot construct instance of `com.walterjwhite.email.organization.api.configuration.rule.AbstractRule` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (FileInputStream); line: 4, column: 10] (through reference chain: com.walterjwhite.email.organization.api.configuration.rule.EmailMatcherRule["rule"])
com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
My configuration is this:
{
"name": "default",
"ordering": "1",
"rule": {
"#class": "com.walterjwhite.email.organization.api.configuration.rule.GroupRule",
"criteriaType": "Should",
"rules": [
{"#class": "com.walterjwhite.email.organization.api.configuration.rule.AttributeRule",
"emailMessageField": "Subject",
"values": ["default"]
}
]
},
"matchType": "ContainsIgnoreCase",
"actionClassNames": [
"com.walterjwhite.email.organization.plugins.count.CountAction",
"com.walterjwhite.email.organization.plugins.index.IndexAction",
"com.walterjwhite.email.organization.plugins.reply.MoveAction"
]
}
On the Java side of things, I am doing this generally:
mapper.readValue(inputStream, entityType);
Now, the entityType in this case is EmailMatcherRule which inside it has a rule field which can either be attribute or group. Inputstream is just the fileInputStream I am passing in ...
I am using Jackson 2.10.1. I also converted the above JSON from YAML which was working fine via Snakeyaml. Note that it automatically embeds the classes into the YAML, so this was a non-issue with it.
Is my JSON correct - according to the documentation, I should be able to add the #class attribute to specify the class I want to use, right?
I tried below and it worked without any configuration. Not sure if thats what you want to achieve:
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
String groupRuleStr = "{\"parentId\":\"parent\",\"groupId\":\"group\"}";
String attributeRuleStr = "{\"parentId\":\"parent\",\"attributeId\":\"attribute\"}";
GroupRule groupRule = mapper.readValue(groupRuleStr, GroupRule.class);
AttributeRule attributeRule = mapper.readValue(attributeRuleStr, AttributeRule.class);
System.out.println(groupRule.groupId);
System.out.println(attributeRule.attributeId);
}
static abstract class AbstractRule {
public String parentId = "parent";
}
static class GroupRule extends AbstractRule {
public String groupId = "group";
}
static class AttributeRule extends AbstractRule {
public String attributeId = "attribute";
}
I had to do this:
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator());
Now, my JSON looks like this (NOTE: this is a different test entity, but you get the idea):
{
"name": "default",
"ordering": "1",
"rule": [
"com.walterjwhite.email.organization.api.configuration.rule.GroupRule",
{
"criteriaType": "Should",
"rules": ["java.util.HashSet",[[
"com.walterjwhite.email.organization.api.configuration.rule.AttributeRule",
{
"emailMessageField": ["com.walterjwhite.email.organization.api.configuration.rule.EmailMessageField", "Subject"],
"values": ["java.util.HashSet", [
"default"
]],
"matchType": ["com.walterjwhite.email.organization.api.configuration.rule.MatchType","ContainsIgnoreCase"]
}]]
]
}
],
"actionClassNames": ["java.util.ArrayList",[
"com.walterjwhite.email.organization.plugins.count.CountAction",
"com.walterjwhite.email.organization.plugins.index.IndexAction",
"com.walterjwhite.email.organization.plugins.reply.MoveAction"
]
]
}
So, the reference documentation I saw with #class seems inaccurate. I am not really happy about adding all this extra information especially when some of it isn't needed - java.util.ArrayList.

How to handle List<String> in Realm?

I have tried add the JSON response into the Realm database. I handled the response through GSON and then tried to convert to realm. I have already extended RealmObject for my response model class. I am also using RealmString class for handling List by using RealmList. But when I tried to GSON to Realm object I get errors. I am looking for an example of this kind if anyone has one. All support are appreciated. Below is my JSON response.
{
"transactionType": 12,
"location": {
"type": "Point",
"coordinates": [
77.7,
12.9
]
},
"rooms": {
"bedrooms": {
"total": 2,
"metadata": [
{
"name": "bedroom 2",
"images": [
"Eshant",
"Abhijeet"
]
}
]
}
}
}
I answered a very similar question here https://stackoverflow.com/a/39993141/1666063
Here is short walkthrough how to to JSON -> GSON -> Realm:
Use http://www.jsonschema2pojo.org/ to generate a POJO with getters and setters for GSON
for the classes and subclasses you want to store in Realm add extends RealmObject to them
for all your classes that extends RealmObject make sure to put #PrimaryKey on of the fields (like an ID)
replace any usage of List<Foo> with RealmList<Foo>
Foo MUST extends RealmObject as well (even if it is a String)
Add a TypeAdapter to GSON that can handle RealmList(here is one I wrote that takes a generic T)

Swagger-annotation generation

I have a problem generating a swagger.json file with swagger annotations. The problem is with the generation of map with array.
Ex:
I have an #ApiModel with a field:
#JsonProperty
private Map<String, String[]> example;
When it generates it looks like this:
"example" : {
"type" : "object",
"additionalProperties" : {
"$ref" : "#/definitions/Array"
}
}
"Array" : {
"type" : "object"
},
When I create my client class with swagger-codegen based on the generated json, it resolve to:
private Map<String, Array> example = new HashMap<String, Array>();
But Array doesn`t exist.
Based on what I`ve seen, the json should look like this:
"definitions": {
"example": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
Is there anyway to make it works ?
I use: Dropwizard, Jersey2, Swagger, JAX-RS

Categories

Resources