Hierarchical POJOs not being properly serialized to JSON by RESTEasy/Jackson - java

I have two POJOs defined as follows,
public class VertexDefinition {
private final String name;
private final Vertex vertex;
public VertexDefinition(String name, Vertex vertex) {
this.name = name;
this.vertex = vertex;
}
#JsonProperty("name")
public String getName() {
return name;
}
#JsonProperty("properties")
public Iterable<PropertyDefinition> getProperties() {
if(vertex == null) {
return Collections.emptySet();
}
return Iterables.transform(vertex.getPropertyKeys(), new Function<String, PropertyDefinition>() {
#Nullable #Override public PropertyDefinition apply(#Nullable String s) {
return new PropertyDefinition(vertex, s);
}
});
}
#JsonProperty("propertyKeys")
public Iterable<String> getPropertyKeys() {
if (vertex == null) {
return Collections.emptySet();
}
return vertex.getPropertyKeys();
}
}
public class PropertyDefinition {
private final Vertex vertex;
private final String propertyName;
public PropertyDefinition(Vertex vertex, String propertyName) {
this.vertex = vertex;
this.propertyName = propertyName;
}
#JsonProperty("name")
public String getName() {
return propertyName;
}
#JsonProperty("type")
public String getType() {
final Object property = vertex.getProperty(propertyName);
if (property != null) {
return property.getClass().getTypeName();
}
return "(unknown)";
}
}
My Rest method looks as follows,
public Iterable<VertexDefinition> getSchema() {
.....
}
When I make a request I get a json response as follows,
[
{
"name" : "Foo",
"properties" : [],
"propertyKeys" : [
"a",
"b",
"c"
]
},
{
"name" : "Bar",
"properties" : [],
"propertyKeys" : [
"a",
"b",
"c"
]
}
]
In short I get an empty array returned for properties while the propertyKeys is filled in.
What am I doing wrong?

I don't think deserialization into an iterable works as you've tried. Could you try something like this instead in your getProperties method?
List<PropertyDefinition> propertyDefinitions = Arrays.asList(mapper.readValue(json, PropertyDefinition[].class))

Related

I need to test my entity classes using a parse tool to ensure that everything is working

I have given a json format which is like below and I am asked to convert this json format to entity classes.
{
"descriptor": {
"reportName": "Shop Drawing Progress Report",
"subLabel": "My Workflow Project",
"columnGroups": [
{
"groupName": "mainData",
"groupLabel": "",
"frozen": true,
"columns": [
{
"field": "identifier",
"label": "Workflow Prefix",
"sortable": true,
"editable": false,
"dataType": "String"
}
]
}]
I create entity classes from above json string and one of those entity class sample is below
public class TabularColumn {
private String field;
private String label;
private boolean sortable;
private boolean editable;
private String dataType;
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public boolean isSortable() {
return sortable;
}
public void setSortable(boolean sortable) {
this.sortable = sortable;
}
public boolean isEditable() {
return editable;
}
public void setEditable(boolean editable) {
this.editable = editable;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
I have to test using parseDesciptor tool which is there in my application to make sure my entity classes generated from the json format are correct.How can I do that?
Here is my parseDecriptor tool which I am using in my java application
public <T> T parseDescriptor(String json, Class<T> c) throws IOException {
try {
ObjectMapper mapper = new ObjectMapper();
mapper.getDeserializationConfig().disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.getDeserializationConfig().enable(DeserializationConfig.Feature.USE_ANNOTATIONS);
T ret = mapper.readValue(json, c);
if (!(ret instanceof ReportDescriptor)) {
throw new IllegalArgumentException("The specified class of type "+c.getCanonicalName()+" does not extend ReportDescriptor");
}
return ret;
}

Unable to retrieve document - Castexception ParameterizedType

I'm new to mongodb and struggle a bit. I want to store a class which contains a HashMap which contains other objects. When I store the object it works without any error and the document in the database looks good. But retrieving the document results in an error:
Caused by: java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
My (simplified) classes look like this:
#Entity(value = "abbyy_parameters", noClassnameStored = true)
public class AbbyyParameters extends AbstractModifiableMongoBean {
private String wordListEncoding = DEFAULT_ENCODING;
private String description;
private String name;
private PredefinedProfile predefinedProfile;
#Embedded
private CustomProfile customProfile;
private Parameters wordListActionParameters;
private Boolean treatBarcodeAsWord;
private Boolean documentProcessingEnabled;
private Boolean documentExportEnabled;
private Integer ocrPageLimit;
private Boolean highCommaFixEnabled;
private Double skewAngle;
private List<RegexBasedLanguage> regexBasedLanguages = new ArrayList<>(2);
public AbbyyParameters() {
this.createNewId();
this.setPredefinedProfile(new PredefinedProfile(PredefinedProfileType.DEFAULT));
this.setCustomProfile(new CustomProfile());
}
public String getWordListEncoding() {
return wordListEncoding;
}
public void setWordListEncoding(String encoding) {
if (!TangroUtils.isNullOrBlankString(encoding)) {
this.wordListEncoding = encoding;
}
}
public PredefinedProfile getPredefinedProfile() {
return predefinedProfile;
}
public void setPredefinedProfile(PredefinedProfile profile) {
if (profile == null) {
profile = new PredefinedProfile("Default");
}
this.predefinedProfile = profile;
}
public CustomProfile getCustomProfile() {
return customProfile;
}
public void setCustomProfile(CustomProfile profile) {
this.customProfile = profile;
}
public Optional<Boolean> isBarcodeTreatedAsWord() {
return Optional.ofNullable(treatBarcodeAsWord);
}
public void treatBarcodeAsWord(Boolean treatBarcodeAsWord) {
this.treatBarcodeAsWord = treatBarcodeAsWord;
}
public Optional<Boolean> isDocumentProcessingEnabled() {
return Optional.ofNullable(documentProcessingEnabled);
}
public void enableDocumentProcessing(Boolean enableDocumentProcessing) {
this.documentProcessingEnabled = enableDocumentProcessing;
}
public Optional<Boolean> isDocumentExportEnabled() {
return Optional.ofNullable(documentExportEnabled);
}
public void enableDocumentExport(Boolean exportDocument) {
this.documentExportEnabled = exportDocument;
}
public Optional<String> getDescription() {
return Optional.ofNullable(description);
}
public void setDescription(String description) {
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Entity
public class CustomProfile {
private static final String DEFAULT_FILE_NAME = "custom";
#Transient
private String name;
#Embedded
private Map<String, ProfileProperties> properties = new HashMap<>(5);
public CustomProfile() {
}
public String getName() {
return name;
}
private void setName (String name) {
this.name = name;
}
public Map<String, ProfileProperties> getProperties() {
return properties;
}
private void setProperties(Map<String, ProfileProperties> properties) {
this.properties = properties;
}
}
#Embedded
public class ProfileProperties implements Iterable<ProfileProperty>, Serializable {
private static final long serialVersionUID = 1L;
#Embedded
private List<ProfileProperty> properties = new ArrayList<>(15);
public List<ProfileProperty> getProperties() {
return properties;
}
public void setProperties(List<ProfileProperty> properties) {
this.properties = properties;
}
public void add(ProfileProperty property) {
Optional<ProfileProperty> oldPropertyOpt = get(property.getName());
if (oldPropertyOpt.isPresent()) {
ProfileProperty oldProperty = oldPropertyOpt.get();
oldProperty.setValue(property.getValue());
} else {
properties.add(property);
}
}
public Optional<ProfileProperty> get(String propertyName) {
if (propertyName == null) {
return Optional.empty();
}
for(ProfileProperty property : properties) {
if (propertyName.equals(property.getName())) {
return Optional.of(property);
}
}
return Optional.empty();
}
#Override
public Iterator<ProfileProperty> iterator() {
return properties.iterator();
}
}
#Embedded
public class ProfileProperty implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String value;
public ProfileProperty(String name, String value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
I created morphia and told it how to map:
morphia = new Morphia();
morphia.map(AbbyyParameters.class,
CustomProfile.class,
ProfileProperties.class,
ProfileProperty.class);
After storing the class in the database the document look like this:
{
"_id" : ObjectId("5b2906a0cac45b8d42bbda91"),
"wordListEncoding" : "ISO-8859-15",
"description" : "",
"name" : "1",
"predefinedProfile" : {
"type" : "DEFAULT"
},
"customProfile" : {
"properties" : {
"PageAnalysisParams" : {
"properties" : [
{
"name" : "DetectBarcodes",
"value" : "true"
}
]
},
"RecognizerParams" : {
"properties" : [
{
"name" : "TextLanguage",
"value" : "English,German,Digits,French,Italian,Spanish,Croatian,Slovak,Bulgarian"
}
]
}
}
},
"treatBarcodeAsWord" : false,
"documentExportEnabled" : false,
"creationDate" : ISODate("2018-06-19T13:35:26.019Z"),
"changedDate" : ISODate("2018-06-19T13:35:28.441Z")
}
When I try to retrieve the document I get the following error:
Caused by: java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
at org.mongodb.morphia.mapping.EmbeddedMapper.readMap(EmbeddedMapper.java:166)
I stepped into the code so I found that this code raises the exception:
new EphemeralMappedField((ParameterizedType) mf.getSubType(), mf, mapper);
mf.getSubType() returns ProfileProperties so I guess I have misconfigured something there?
What do I have to do that I can retrieve my document?

I get null fields when I try to deserialize JSON with GSON

The Gist
I tried to deserialize some JSON text with GSON. The JSON string had values defined. However, the deserialized string has null values.
Exactly what I did
I tried to deserialize some JSON text with GSON
SomeSpec deserializedJson = GSON.fromJson(serializedJson, SomeSpec.class);
where serializedJson is a string containing
{
"some_class": "abc.def.SomeClass",
"stuff": [
"FOO",
"BAR",
],
"definition": {
"values": [
{ "feature": "FOO", "value": 1.0 },
{ "feature": "BAR", "value": 1.0 },
]
}
}
and SomeSpec is a java class containing:
package somepackagepath;
import java.util.List;
public class SomeSpec {
private List<FeatureValueSpec> _values;
private List<String> _postProcessFunctions;
public List<FeatureValueSpec> getValues() {
return _values;
}
public List<String> getPostProcessFunctions() {
return _postProcessFunctions;
}
public static class FeatureValueSpec {
private String _feature;
private float _value;
public String getFeature() {
return _feature;
}
public float getValue() {
return _value;
}
}
}
The deserialized object had only null fields even though the JSON clearly had those fields defined.
First: There are two errors in your JSON in Arrays. There are extra commas at end of each array.
Second your models should look like this
public class Values
{
private String value;
private String feature;
public String getValue ()
{
return value;
}
public void setValue (String value)
{
this.value = value;
}
public String getFeature ()
{
return feature;
}
public void setFeature (String feature)
{
this.feature = feature;
}
}
public class Definition
{
private Values[] values;
public Values[] getValues ()
{
return values;
}
public void setValues (Values[] values)
{
this.values = values;
}
}
public class MyPojo
{
private Definition definition;
private String[] stuff;
private String some_class;
public Definition getDefinition ()
{
return definition;
}
public void setDefinition (Definition definition)
{
this.definition = definition;
}
public String[] getStuff ()
{
return stuff;
}
public void setStuff (String[] stuff)
{
this.stuff = stuff;
}
public String getSome_class ()
{
return some_class;
}
public void setSome_class (String some_class)
{
this.some_class = some_class;
}
}

How to read JSON file to Java

How to write code to read and display key and value from web_block, port_block and user?
My JSON file test.json:
{
"web_block":[
{
"url" : "www.facebook.com",
"action" : "deny"
},
{
"url" : "www.google.com",
"action" : "deny"
},
{
"url" : "www.youtube.com",
"action" : "deny"
},
{
"url" : "www.wu.ac.th",
"action" : "allow"
}
],
"port_block":[
{
"port" : "80",
"protocol" : "tcp",
"action" : "block"
},
{
"port" : "443",
"protocol" : "udp",
"action" : "allow"
}
],
"user": [
{
"username" : "toms"
}
]
}
I tried following:
JSONParser parser = new JSONParser();
try {
Object obj = parser.parse(new FileReader("d:\\test.json"));
JSONObject jsonObject = (JSONObject) obj;
String name = (String) jsonObject.get("web_block");
System.out.println(url);
long age = (Long) jsonObject.get("port_block");
System.out.println(port);
but it is still wrong.
Add the following Jackson libraries to your project -
jackson-databind
jackson-annotations
jackson-core
Create a pojo class mapped to your json -
public class CustomJsonData{
#JsonProperty("web_block")
private List<WebBlock> webBlock = new ArrayList<WebBlock>();
#JsonProperty("port_block")
private List<PortBlock> portBlock = new ArrayList<PortBlock>();
#JsonProperty("user")
private List<User> user = new ArrayList<User>();
public CustomJsonData() {
}
public List<WebBlock> getWebBlock() {
return webBlock;
}
public void setWebBlock(List<WebBlock> webBlock) {
this.webBlock = webBlock;
}
public List<PortBlock> getPortBlock() {
return portBlock;
}
public void setPortBlock(List<PortBlock> portBlock) {
this.portBlock = portBlock;
}
public List<User> getUser() {
return user;
}
public void setUser(List<User> user) {
this.user = user;
}
}
class PortBlock {
#JsonProperty("port")
private String port;
#JsonProperty("protocol")
private String protocol;
#JsonProperty("action")
private String action;
public PortBlock() {
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
}
class User {
#JsonProperty("username")
private String username;
public User() {
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
class WebBlock {
#JsonProperty("url")
private String url;
#JsonProperty("action")
private String action;
public WebBlock() {
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
}
Explanation: Data in your json present under "[ ]" is an array, so it is mapped with array list, where as data under "{ }" is an object, so it is mapped with a particular class (example: WebBlock, PortBlock etc) which is having fields of string type.
Now you can retrieve data like below -
ObjectMapper mapper = new ObjectMapper();
CustomJsonData object = mapper.readValue(new FileReader("d:\\test.json"),CustomJsonData.class);
String username = object.getUser().get(0).getUsername();
List<WebBlock> webBlocks = object.getWebBlock();
List<PortBlock> portBlocks = object.getPortBlock();
Refer the examples here - http://wiki.fasterxml.com/JacksonInFiveMinutes

Deserialize dynamic json using jackson JsonTypeInfo property as ENUM?

I am trying to get java object from dynamic JSON.
One Important point these given classes are from third party API.
#JsonTypeInfo(
use = Id.NAME,
include = As.PROPERTY,
property = "nodeType"
)
#JsonSubTypes({ #Type(
name = "Filter",
value = Filter.class
), #Type(
name = "Criterion",
value = Criterion.class
)})
public abstract class Node {
public Node() {
}
#JsonIgnore
public EvaluationResult evaluate(Map<UUID, List<AnswerValue>> answers) {
Evaluator evaluator = new Evaluator();
return evaluator.evaluateAdvancedLogic(this, answers);
}
}
Filter.java
#JsonInclude(Include.NON_NULL)
#JsonPropertyOrder({"evaluationType", "filters"})
public class Filter extends Node {
#JsonProperty("evaluationType")
private EvaluationType evaluationType;
#NotNull
#JsonProperty("filters")
#Valid
private List<Node> filters = new ArrayList();
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap();
public Filter() {
}
#JsonProperty("evaluationType")
public EvaluationType getEvaluationType() {
return this.evaluationType;
}
#JsonProperty("evaluationType")
public void setEvaluationType(EvaluationType evaluationType) {
this.evaluationType = evaluationType;
}
#JsonProperty("filters")
public List<Node> getFilters() {
return this.filters;
}
#JsonProperty("filters")
public void setFilters(List<Node> filters) {
this.filters = filters;
}
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
}
Criterion.java
#JsonInclude(Include.NON_NULL)
#JsonPropertyOrder({"fieldSourceType", "fieldCategoryName", "sequenceNumber", "fieldName", "values", "operator", "fieldId"})
public class Criterion extends Node {
#JsonProperty("fieldSourceType")
private FieldSourceType fieldSourceType;
#JsonProperty("fieldCategoryName")
private String fieldCategoryName;
#NotNull
#JsonProperty("sequenceNumber")
private Long sequenceNumber;
#JsonProperty("fieldName")
private String fieldName;
#JsonProperty("values")
#Valid
private List<String> values = new ArrayList();
#JsonProperty("operator")
#Valid
private Operator operator;
#NotNull
#JsonProperty("fieldId")
private UUID fieldId;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap();
public Criterion() {
}
#JsonProperty("fieldSourceType")
public FieldSourceType getFieldSourceType() {
return this.fieldSourceType;
}
#JsonProperty("fieldSourceType")
public void setFieldSourceType(FieldSourceType fieldSourceType) {
this.fieldSourceType = fieldSourceType;
}
#JsonProperty("fieldCategoryName")
public String getFieldCategoryName() {
return this.fieldCategoryName;
}
#JsonProperty("fieldCategoryName")
public void setFieldCategoryName(String fieldCategoryName) {
this.fieldCategoryName = fieldCategoryName;
}
#JsonProperty("sequenceNumber")
public Long getSequenceNumber() {
return this.sequenceNumber;
}
#JsonProperty("sequenceNumber")
public void setSequenceNumber(Long sequenceNumber) {
this.sequenceNumber = sequenceNumber;
}
#JsonProperty("fieldName")
public String getFieldName() {
return this.fieldName;
}
#JsonProperty("fieldName")
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
#JsonProperty("values")
public List<String> getValues() {
return this.values;
}
#JsonProperty("values")
public void setValues(List<String> values) {
this.values = values;
}
#JsonProperty("operator")
public Operator getOperator() {
return this.operator;
}
#JsonProperty("operator")
public void setOperator(Operator operator) {
this.operator = operator;
}
#JsonProperty("fieldId")
public UUID getFieldId() {
return this.fieldId;
}
#JsonProperty("fieldId")
public void setFieldId(UUID fieldId) {
this.fieldId = fieldId;
}
}
The json used to conversion is this.
{
"evaluationType":"AND",
"nodeType":"Criterion",
"Criterion":[
{
"fieldName":"sdada",
"values":"sdad",
"operator":{
"operatorType":"Equals"
}
},
{
"nodeType":"Criterion",
"fieldName":"dasa",
"values":"das",
"operator":{
"operatorType":"Equals"
}
},
{
"nodeType":"Criterion",
"fieldName":"dada",
"values":"dads",
"operator":{
"operatorType":"Equals"
}
}
]
}
The problem is that deserialization of this JSON fails with following error:
{
"message": "Class com.cvent.logic.model.Criterion is not assignable to com.cvent.logic.model.Filter"
}
The first part of the JSON is wrong
{
"evaluationType":"AND",
"nodeType":"Criterion",
"Criterion":[
It says that the type is Criterion but it has evaluationType from Filter.
Also, probably "Criterion" : [ should be "filters" : [

Categories