EclipseLink MOXy JSON Serialization - java

I have got a sample class:
class Zoo {
public Collection<? extends Animal> animals;
}
When serialized with MOXy, I am getting:
{
"bird": [
{
"name": "bird-1",
"wingSpan": "6 feets",
"preferredFood": "food-1"
}
],
"cat": [
{
"name": "cat-1",
"favoriteToy": "toy-1"
}
],
"dog": [
{
"name": "dog-1",
"breed": "bread-1",
"leashColor": "black"
}
]
}
Why is it using array indicators "[]", while bird, cat, and dog are not arrays?
Second, is there a way to get rid of "bird", "cat", and "dog"?
In other words, I am trying to get to:
{
{
"name": "bird-1",
"wingSpan": "6 feets",
"preferredFood": "food-1"
}
,
{
"name": "cat-1",
"favoriteToy": "toy-1"
}
,
{
"name": "dog-1",
"breed": "bread-1",
"leashColor": "black"
}
}
Thanks,
Behzad

QUESTION #1
Why is it using array indicators "[]", while bird, cat, and dog are
not arrays?
To get this JSON representation you have mapped your model with the #XmlElementRef annotation which tells JAXB to use the value of the #XmlRootElement annotation as the inheritance indicator. With MOXy's JSON binding these become keys. We make the value of these keys JSON arrays since keys are not allowed to repeat.
Zoo
In your model you have the #XmlElementRef annotation on your animals field/property.
import java.util.Collection;
import javax.xml.bind.annotation.XmlElementRef;
class Zoo {
#XmlElementRef
public Collection<? extends Animal> animals;
}
Animal
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlSeeAlso({Bird.class, Cat.class, Dog.class})
public abstract class Animal {
private String name;
}
Bird
On each of your subclasses you have an #XmlRootElement annotation.
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Bird extends Animal {
private String wingSpan;
private String preferredFood;
}
input.json/Output
{
"bird" : [ {
"name" : "bird-1",
"wingSpan" : "6 feets",
"preferredFood" : "food-1"
} ],
"cat" : [ {
"name" : "cat-1",
"favoriteToy" : "toy-1"
} ],
"dog" : [ {
"name" : "dog-1",
"breed" : "bread-1",
"leashColor" : "black"
} ]
}
For More Information
http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html
QUESTION #2
Second, is there a way to get rid of "bird", "cat", and "dog"?
You are going to need some sort of inheritance indicator to represent the various subclasses.
OPTION #1 - #XmlDescriminatorNode/#XmlDescriminatorValue
Here I do this using MOXy's #XmlDescriminatorNode/#XmlDescriminatorValue annotations.
Zoo
import java.util.Collection;
class Zoo {
public Collection<? extends Animal> animals;
}
Animal
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorNode;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlSeeAlso({Bird.class, Cat.class, Dog.class})
#XmlDiscriminatorNode("#type")
public abstract class Animal {
private String name;
}
Bird
import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorValue;
#XmlDiscriminatorValue("bird")
public class Bird extends Animal {
private String wingSpan;
private String preferredFood;
}
input.json/Output
{
"animals" : [ {
"type" : "bird",
"name" : "bird-1",
"wingSpan" : "6 feets",
"preferredFood" : "food-1"
}, {
"type" : "cat",
"name" : "cat-1",
"favoriteToy" : "toy-1"
}, {
"type" : "dog",
"name" : "dog-1",
"breed" : "bread-1",
"leashColor" : "black"
} ]
}
For More Information
http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-moxy-extension.html
OPTION #2 - #XmlClassExtractor
ClassExtractor (AnimalExtractor)
You can write some code that will determine the appropriate subclass based on the JSON content.
import org.eclipse.persistence.descriptors.ClassExtractor;
import org.eclipse.persistence.sessions.*;
public class AnimalExtractor extends ClassExtractor {
#Override
public Class extractClassFromRow(Record record, Session session) {
if(null != record.get("#wingSpan") || null != record.get("#preferredFood")) {
return Bird.class;
} else if(null != record.get("#favoriteToy")) {
return Cat.class;
} else {
return Dog.class;
}
}
}
Animal
The #XmlClassExtractor annotation is used to specify the ClassExtractor.
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlClassExtractor;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlSeeAlso({Bird.class, Cat.class, Dog.class})
#XmlClassExtractor(AnimalExtractor.class)
public abstract class Animal {
private String name;
}
Bird
Due to how MOXy processes the #XmlElement and #XmlAttribute annotations, any of the data you want to be made available to the ClassExtractor will need to be annotated with #XmlAttribute.
import javax.xml.bind.annotation.XmlAttribute;
public class Bird extends Animal {
#XmlAttribute
private String wingSpan;
#XmlAttribute
private String preferredFood;
}
input.json/Output
{
"animals" : [ {
"wingSpan" : "6 feets",
"preferredFood" : "food-1",
"name" : "bird-1"
}, {
"favoriteToy" : "toy-1",
"name" : "cat-1"
}, {
"breed" : "bread-1",
"leashColor" : "black",
"name" : "dog-1"
} ]
}
For More Information
http://blog.bdoughan.com/2012/02/jaxb-and-inheritance-eclipselink-moxy.html
DEMO CODE
The following demo code can be used with both of the mappings described above.
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
JAXBContext jc = JAXBContext.newInstance(new Class[] {Zoo.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StreamSource json = new StreamSource("src/forum14210676/input.json");
Zoo zoo = unmarshaller.unmarshal(json, Zoo.class).getValue();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(zoo, System.out);
}
}

Related

Parse json-ld generated by Apache Any23 into Java Pojo using Jackson

I want to map structured data (microdata, jsonld) extracted from html text into a Java POJO. For extraction I use the library Apache Any23 and configured a JSONLDWriter to convert the structured data found in the html document into json-ld format.
This works as expected an gives me the following output:
[ {
"#graph" : [ {
"#id" : "_:node1gn1v4pudx1",
"#type" : [ "http://schema.org/JobPosting" ],
"http://schema.org/datePosted" : [ {
"#language" : "en-us",
"#value" : "Wed Jan 11 02:00:00 UTC 2023"
} ],
"http://schema.org/description" : [ {
"#language" : "en-us",
"#value" : "Comprehensive Job Description"
} ],
"http://schema.org/hiringOrganization" : [ {
"#language" : "en-us",
"#value" : "Org AG"
} ],
"http://schema.org/jobLocation" : [ {
"#id" : "_:node1gn1v4pudx2"
} ],
"http://schema.org/title" : [ {
"#language" : "en-us",
"#value" : "Recruiter (m/f/d)\n "
} ]
}, {
"#id" : "_:node1gn1v4pudx2",
"#type" : [ "http://schema.org/Place" ],
"http://schema.org/address" : [ {
"#id" : "_:node1gn1v4pudx3"
} ]
}, {
"#id" : "_:node1gn1v4pudx3",
"#type" : [ "http://schema.org/PostalAddress" ],
"http://schema.org/addressCountry" : [ {
"#language" : "en-us",
"#value" : "Company Country"
} ],
"http://schema.org/addressLocality" : [ {
"#language" : "en-us",
"#value" : "Company City"
} ],
"http://schema.org/addressRegion" : [ {
"#language" : "en-us",
"#value" : "Company Region"
} ]
}, {
"#id" : "https://career.company.com/job/Recruiter/",
"http://www.w3.org/1999/xhtml/microdata#item" : [ {
"#id" : "_:node1gn1v4pudx1"
} ]
} ],
"#id" : "https://career.company.com/job/Recruiter/"
} ]
Next I want to deserialize the json-ld object into a Java bean using jackson. The POJO class should look somthing like this:
public class JobPosting {
private String datePosting;
private String hiringOrganization;
private String title;
private String description;
// Following members could be enclosed in a class too if easier
// Like class Place{private PostalAddress postalAddress;}
// private Place place;
private String addressCountry;
private String addressLocality;
private String addressRegion;
}
I would like to do it with annotations provided by Jackson lib but I struggle with a few things:
The #type value wrapped with an array node
The actual data has an extra #value layer
And some objects only hold a reference to other objects in the graph via #id fields
How can I map these fields to my Java Pojo properly?
The trick is to process the json-ld with a json-ld processor to get a more developer friendly json. The titanium-json-ld library provides such processors.
JsonDocument input = JsonDocument.of(jsonLdAsInputStream);
JsonObject frame = JsonLd.frame(input, URI.create("http://schema.org")).get();
The above code snippet resolves references via #id and resolves json keys with the given IRI.
That leads to the following output which is easy to parse via Jackson lib:
[{
"id": "_:b0",
"type": "JobPosting",
"datePosted": {
"#language": "en-us",
"#value": "Wed Jan 11 02:00:00 UTC 2023"
},
"description": {
"#language": "en-us",
"#value": "Comprehensive Job Description"
},
"hiringOrganization": {
"#language": "en-us",
"#value": "Org AG"
},
"jobLocation": {
"id": "_:b1",
"type": "Place",
"address": {
"id": "_:b2",
"type": "PostalAddress",
"addressCountry": {
"#language": "en-us",
"#value": "Company Country"
},
"addressLocality": {
"#language": "en-us",
"#value": "Company City"
},
"addressRegion": {
"#language": "en-us",
"#value": "Company Region"
}
}
},
"title": {
"#language": "en-us",
"#value": "Recruiter (m/f/d)\n "
}
}]
Looking the elements you are interested in the json (for example the "datePosted", "hiringOrganization" values) they are always labelled by "#value" and included in the array corresponding to their names (in this case "http://schema.org/datePosted" and "http://schema.org/hiringOrganization". These are all contained in a part of your json file that can be converted to a JsonNode node that can be obtained in the following way:
JsonNode root = mapper.readTree(json)
.get(0)
.get("#graph")
.get(0);
So if you have a pojo like below:
#Data
public class JobPosting {
private String datePosted;
private String hiringOrganization;
}
and you want to retrieve the datePosted and hiringOrganization values you can check that the relative position is still the same in the json file and can be calculated in a for loop:
JsonNode root = mapper.readTree(json)
.get(0)
.get("#graph")
.get(0);
String strSchema = "http://schema.org/";
String[] fieldNames = {"datePosted", "hiringOrganization"};
//creating a Map<String, String> that will be converted to the JobPosting obj
Map<String, String> map = new HashMap<>();
for (String fieldName: fieldNames) {
map.put(fieldName,
root.get(strSchema + fieldName)
.get(0)
.get("#value")
.asText()
);
}
JobPosting jobPosting = mapper.convertValue(map, JobPosting.class);
//it prints JobPosting(datePosted=Wed Jan 11 02:00:00 UTC 2023, hiringOrganization=Org AG)
System.out.println(jobPosting);
This would require some preprocessing first to turn your graph with id pointers into a simplified tree before mapping it with Jackson:
Turn it into a tree by replacing the #id references with the actual objects themselves.
Flatten those troublesome object/array wrappers around #value.
Full code below, using Java 17 and a bit of recursion:
package org.example;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import static java.util.stream.Collectors.toMap;
class Main {
public static void main(String[] args) throws Exception {
var mapper = new ObjectMapper();
var node = mapper.readValue(new File("test.json"), Object.class);
// Build a lookup map of "#id" to the actual object.
var lookup = buildLookup(node, new HashMap<>());
// Replace "#id" references with the actual objects themselves instead
var referenced = lookupReferences(node, lookup);
// Flattens single object array containing "#value" to be just the "#value" themselves
var flattened = flatten(referenced);
// Jackson should be able to under our objects at this point, so convert it
var jobPostings =
mapper.convertValue(flattened, new TypeReference<List<RootObject>>() {}).stream()
.flatMap(it -> it.graph().stream())
.filter(it -> it instanceof JobPosting)
.map(it -> (JobPosting) it)
.toList();
System.out.println(jobPostings);
}
private static Map<String, Object> buildLookup(Object node, Map<String, Object> lookup) {
if (node instanceof List<?> list) {
for (var value : list) {
buildLookup(value, lookup);
}
} else if (node instanceof Map<?, ?> map) {
for (var value : map.values()) {
buildLookup(value, lookup);
}
if (map.size() > 1 && map.get("#id") instanceof String id) {
lookup.put(id, node);
}
}
return lookup;
}
private static Object lookupReferences(Object node, Map<String, Object> lookup) {
if (node instanceof List<?> list
&& list.size() == 1
&& list.get(0) instanceof Map<?, ?> map
&& map.size() == 1
&& map.get("#id") instanceof String id) {
return lookupReferences(lookup.get(id), lookup);
}
if (node instanceof List<?> list) {
return list.stream().map(value -> lookupReferences(value, lookup)).toList();
}
if (node instanceof Map<?, ?> map) {
return map.entrySet().stream()
.map(entry -> Map.entry(entry.getKey(), lookupReferences(entry.getValue(), lookup)))
.collect(toMap(Entry::getKey, Entry::getValue));
}
return node;
}
private static Object flatten(Object node) {
if (node instanceof List<?> list && list.size() == 1) {
if (list.get(0) instanceof String s) {
return s;
}
if (list.get(0) instanceof Map<?, ?> map) {
var value = map.get("#value");
if (value != null) {
return value;
}
}
}
if (node instanceof List<?> list) {
return list.stream().map(Main::flatten).toList();
}
if (node instanceof Map<?, ?> map) {
return map.entrySet().stream()
.map(entry -> Map.entry(entry.getKey(), flatten(entry.getValue())))
.collect(toMap(Entry::getKey, Entry::getValue));
}
return node;
}
}
#JsonIgnoreProperties(ignoreUnknown = true)
record RootObject(#JsonProperty("#graph") List<GraphObject> graph) {}
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "#type", defaultImpl = Ignored.class)
#JsonSubTypes({
#JsonSubTypes.Type(value = JobPosting.class, name = "http://schema.org/JobPosting"),
#JsonSubTypes.Type(value = Place.class, name = "http://schema.org/Place"),
#JsonSubTypes.Type(value = PostalAddress.class, name = "http://schema.org/PostalAddress"),
})
interface GraphObject {}
#JsonIgnoreProperties(ignoreUnknown = true)
record Ignored() implements GraphObject {}
#JsonIgnoreProperties(ignoreUnknown = true)
record JobPosting(
#JsonProperty("http://schema.org/title") String title,
#JsonProperty("http://schema.org/description") String description,
#JsonProperty("http://schema.org/hiringOrganization") String hiringOrganization,
#JsonProperty("http://schema.org/datePosted") String datePosted,
#JsonProperty("http://schema.org/jobLocation") Place jobLocation)
implements GraphObject {}
#JsonIgnoreProperties(ignoreUnknown = true)
record Place(#JsonProperty("http://schema.org/address") PostalAddress address)
implements GraphObject {}
#JsonIgnoreProperties(ignoreUnknown = true)
record PostalAddress(
#JsonProperty("http://schema.org/addressLocality") String locality,
#JsonProperty("http://schema.org/addressRegion") String region,
#JsonProperty("http://schema.org/addressCountry") String country)
implements GraphObject {}

How have Jackson use toString method if object have no public accessors?

I am looking for a solution that have Jackson use toString method whenever it can not serialize an object type.
Let me explain more detail.
I have a class:
#AllArgsConstructor
public class TestJackson {
public String RequestId;
public AntiSerialize foo;
#JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public LocalDateTime dateRequest;
public Map<String, Object> headers;
private static class AntiSerialize {
#Override
public String toString() {
return "AntiSerialize " + ZonedDateTime.now().toEpochSecond();
}
}
public static TestJackson createSample() {
return new TestJackson(
"123",
new TestJackson.AntiSerialize(),
LocalDateTime.now(),
Map.of("content", 999,
"b3", new TestJackson.AntiSerialize(),
"b4", Arrays.asList(
new TestJackson.AntiSerialize(),
new TestJackson.AntiSerialize()
)
)
);
}
}
This is to test serialize object
var OM = new ObjectMapper()
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
try {
//var f = TestJackson.createSample().foo;
//out.println(((Object)f).toString());
var json = OM.writerWithDefaultPrettyPrinter()
.writeValueAsString(TestJackson.createSample());
out.println(json);
} catch (Exception e) {
e.printStackTrace(out);
}
It prints
{
"RequestId" : "123",
"foo" : { },
"dateRequest" : "2022-08-04 09:04:14",
"headers" : {
"b3" : { },
"b4" : [ { }, { } ],
"content" : 999
}
}
But I expect:
{
"RequestId" : "123",
"foo" : "AntiSerialize 1659578741",
"dateRequest" : "2022-08-04 09:04:14",
"headers" : {
"b3" : "AntiSerialize 1659578752",
"b4" : [ "AntiSerialize 1659578763", "AntiSerialize 1659578774" ],
"content" : 999
}
}
Assume TestJackson is third party class and can't modify.
AntiSerialize is also a private nested class.

Spring Data MongoDB support for inheritance on a nested object

So My problem is related to how spring handles inheritance when it comes to fields.
I have four classes
#Document(collection = "A")
public class A {
#Id
id;
#Field
B data;
}
public class B {
Type type
}
public class C extends B {
String cField;
public C() {
super(Type.C);
}
}
public class D extends B {
Integer dField;
public D() {
super(Type.D);
}
}
I'm able to store data into mongodb using this schema and it looks something like this
{
"_id" : ObjectId("5f291f861020d19a3db05123"),
"data" : {
"cField" : "abcd",
"type" : "C",
"_class" : "com.example.C"
},
"_class" : "com.example.A"
}
{
"_id" : ObjectId("5f291f861020d19a3db05124"),
"data" : {
"dField" : NumberInt(30),
"type" : "D",
"_class" : "com.example.D"
},
"_class" : "com.example.A"
}
Now when I try to do a findAll on repository, it does not casts to the child class, but simply returns an instance of B.
What changes do I need to make so that I can get correct child object when getting from db?

Json serialize and deserialize with same name

When I call my API with a request body I deserialize it with the variable name in my POJO. I modify the same list and return back but it duplicates the list
#JsonSerialize
#JsonIgnoreProperties(ignoreUnknown = true)
public class UASchema {
#JsonProperty("metric_id")
private ArrayList<String> fMetricId;
#JsonProperty("schema")
private ArrayList<String> fSchema;
#JsonProperty("hash")
private String fHash;
...
...
//getter and setters
}
Request body is
{
"data" : [
{
"metric_id": ["k1", "ak2", "d90"],
"schema": ["s1", "s2"]
},
{
"metric_id": ["k21", "k22"],
"schema": ["a11", "s22"]
}
]
}
Response I get is (added hash)
{
"result": [
{
"fmetricId": [
"k1",
"ak2",
"d90"
],
"fschema": [
"s1",
"s2"
],
"metric_id": [
"k1",
"ak2",
"d90"
],
"schema": [
"s1",
"s2"
],
"hash": "389abc9093442cfd2aee1f20807ba467"
},
{
"fmetricId": [
"k21",
"k22"
],
"fschema": [
"a11",
"s22"
],
"metric_id": [
"k21",
"k22"
],
"schema": [
"a11",
"s22"
],
"hash": "5f366dde65b69fa679f95a81f3115b7f"
}
]
}
It duplicates the list and not correctly serializing it. I want the response to just have the same list as request body and I added hash back.
It looks like your algorithm duplicates entries or you manually generated getters and setters which duplicate output. By default Jackson does not add extra entries. See below example how you can do that, I generated getters and setters in IDE. f-fieldName pattern for fields is outdated and you should use regular names. See, for example, Google's Java Guide:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.File;
import java.util.List;
import java.util.UUID;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
Root root = mapper.readValue(jsonFile, Root.class);
root.getData().forEach(s -> s.setfHash(UUID.randomUUID().toString()));
System.out.println(mapper.writeValueAsString(root));
}
}
class Root {
private List<UASchema> data;
public List<UASchema> getData() {
return data;
}
public void setData(List<UASchema> data) {
this.data = data;
}
#Override
public String toString() {
return "Root{" +
"data=" + data +
'}';
}
}
class UASchema {
#JsonProperty("metric_id")
private List<String> fMetricId;
#JsonProperty("schema")
private List<String> fSchema;
#JsonProperty("hash")
private String fHash;
public List<String> getfMetricId() {
return fMetricId;
}
public void setfMetricId(List<String> fMetricId) {
this.fMetricId = fMetricId;
}
public List<String> getfSchema() {
return fSchema;
}
public void setfSchema(List<String> fSchema) {
this.fSchema = fSchema;
}
public String getfHash() {
return fHash;
}
public void setfHash(String fHash) {
this.fHash = fHash;
}
#Override
public String toString() {
return "UASchema{" +
"fMetricId=" + fMetricId +
", fSchema=" + fSchema +
", fHash='" + fHash + '\'' +
'}';
}
}
Above code prints:
{
"data" : [ {
"metric_id" : [ "k1", "ak2", "d90" ],
"schema" : [ "s1", "s2" ],
"hash" : "80dcf06d-1d83-463c-afb8-edef8efdc71f"
}, {
"metric_id" : [ "k21", "k22" ],
"schema" : [ "a11", "s22" ],
"hash" : "a83d7981-4b80-4318-a632-f3c91d14379b"
} ]
}

"no suitable constructor" error when deserializing JSON children

I'm trying to map a json structure to a pojo using fasterxml/jackson.
My json comes from a file and looks like this:
{
"groups": [
{
"name": "Group1",
"icon": "group1.png",
"banner": "banner.png"
},
{
"name": "Group2",
"icon": "group2.png",
"banner": "banner.png"
}
],
"ticker": [
{
"title": "ticker1",
"description": "description",
"url": "bla",
"icon": "icon.png",
"banner": "banner.png",
"group": "Group1",
"enabled": "true",
"startTime": "00:00",
"startDate": "15.10.2013"
}
]
}
I'm interested in the groups. Therefore I created a class Groups:
public class Groups implements Serializable {
private final static long serialVersionUID = 42L;
private List<Group> groups;
public Groups() {}
public Groups ( List<Group> groups ) {
this.groups = groups;
}
public List<Group> getGroups() {
if (groups == null) {
groups = new ArrayList<Group>();
}
return groups;
}
public void add(Group group) {
getGroups().add(group);
}
}
Usually I am using this code to map a json to a pojo:
public static <T> T readJsonFile(File file, Class<T> valueType) throws IOException {
String json = readJsonFile(file.getAbsolutePath());
if( StringUtils.isEmpty(json) ) {
return null;
}
return createObjectMapper().readValue(json, valueType);
}
This works fine if the pojo is the outer json object.
But if I am trying to extract the groups it fails with:
"no suitable constructor".
How is it possible to extract a pojo that is nested in a json structure?
public Groups() {
groups = new ArrayList<>();
}
The default constructor is used on serialization, and groups is just defined as interface.
I would even change all, and initialize the field to a non-null value.

Categories

Resources