Java Extracting out Initializing private fields of a class - java

Is it possible to solve the following problem using inbuilt Java API? (I want to retain the strict private access as shown)
I have n subclasses of an abstract class BaseModel.
Each of these subclasses declare their own set of private String fields.
Within the subclass constructor, I wish to set the private fields from a Map using Java Reflection. An example of this function:
void setPrivateFields(Map<String, String> fieldsValuesMap) throws NoSuchFieldException, IllegalAccessException {
for (Map.Entry<String, String> entry : fieldsValuesMap.entrySet()) {
String fieldName = entry.getKey();
String fieldValue = entry.getValue();
Field field = this.getClass().getDeclaredField(fieldName);
field.set(this, fieldValue);
}
}
Is it possible to extract out the function I have described in 3) such that I do not have to rewrite the algorithm in all the constructors of the subclasses?
class BaseModel {}
class Project extends BaseModel {
private String name;
private String type;
public Project(Map<String, String> fieldsValuesMap) {
setPrivateFields(fieldsValuesMap);
}
}
class Task extends BaseModel {
private String description;
private String rawDescription;
public Task(Map<String, String> fieldsValuesMap) {
setPrivateFields(fieldsValuesMap);
}
}
class SubTask extends BaseModel {
...
}
...

You could simply add it to the superclass.
class BaseModel {
protected void setPrivateFields(Map<String, String> fieldsValuesMap) {
for (Map.Entry<String, String> entry : fieldsValuesMap.entrySet()) {
String fieldName = entry.getKey();
String fieldValue = entry.getValue();
try {
Field field = this.getClass().getDeclaredField(fieldName);
boolean access = field.isAccessible();
field.setAccessible(true);
field.set(this, fieldValue);
field.setAccessible(access);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}

BaseModel.java
abstract class BaseModel {
}
Project.java
import java.util.Map;
class Project extends BaseModel {
private String name;
private String type;
public Project(Map<String, String> fieldsValuesMap) throws NoSuchFieldException, IllegalAccessException {
Utils.setPrivateFields(this, fieldsValuesMap);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
Task.java
import java.util.Map;
class Task extends BaseModel {
private String description;
private String rawDescription;
public Task(Map<String, String> fieldsValuesMap) throws NoSuchFieldException, IllegalAccessException {
Utils.setPrivateFields(this, fieldsValuesMap);
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getRawDescription() {
return rawDescription;
}
public void setRawDescription(String rawDescription) {
this.rawDescription = rawDescription;
}
}
Utils.java
import java.lang.reflect.Field;
import java.util.Map;
public class Utils {
static void setPrivateFields(BaseModel baseModel, Map<String, String> fieldsValuesMap) throws NoSuchFieldException, IllegalAccessException {
for (Map.Entry<String, String> entry : fieldsValuesMap.entrySet()) {
String fieldName = entry.getKey();
String fieldValue = entry.getValue();
Field field = baseModel.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(baseModel, fieldValue);
}
}
}
Main.java
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Map<String, String> map = new HashMap<>();
map.put("name", "ABC");
map.put("type", "XYZ");
Project project = new Project(map);
System.out.println(project.getName());
System.out.println(project.getType());
}
}

Related

Access to class attributes' values using Java Annotations

I am working with a java example using annotations, I created a simple POJO (java bean) using annotations to its attributes. I want to have the ability to create new objects of this type and retrieve the values of its attributes using the annotations created.
My POJO :
import java.io.Serializable;
import annotations.BusinessObject;
import annotations.BusinessObjectAttribute;
import annotations.BusinessObjectName;
import annotations.BusinessObjectPolicy;
import annotations.BusinessObjectRevision;
import annotations.BusinessObjectVault;
#BusinessObject
public class IndusTask implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
// Mandatory to create new object !
#BusinessObjectName
private String taskName;
#BusinessObjectRevision
private String taskRevision;
#BusinessObjectVault
private String vault;
// Mandatory to invoke iTask.create(context, policy) in Database
#BusinessObjectPolicy
private String policy;
//Specific attributes
#BusinessObjectAttribute
private String taskDescription;
#BusinessObjectAttribute
private String creationDate;
#BusinessObjectAttribute
private Integer weight;
public IndusTask() {
}
public IndusTask(String taskName, String taskRevision, String vault, String policy, String taskDescription,
String creationDate, Integer weight) {
super();
this.taskName = taskName;
this.taskRevision = taskRevision;
this.vault = vault;
this.policy = policy;
this.taskDescription = taskDescription;
this.creationDate = creationDate;
this.weight = weight;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public String getTaskRevision() {
return taskRevision;
}
public void setTaskRevision(String taskRevision) {
this.taskRevision = taskRevision;
}
public String getVault() {
return vault;
}
public void setVault(String vault) {
this.vault = vault;
}
public String getTaskDescription() {
return taskDescription;
}
public void setTaskDescription(String taskDescription) {
this.taskDescription = taskDescription;
}
public String getCreationDate() {
return this.creationDate;
}
public void setCreationDate(String creationDate) {
this.creationDate = creationDate;
}
public Integer getWeight() {
return weight;
}
public void setWeight(Integer weight) {
this.weight = weight;
}
public String getPolicy() {
return policy;
}
public void setPolicy(String policy) {
this.policy = policy;
}
}
Example of attributes' declaration:
*Business Object Type declaration
package annotations;
import java.lang.annotation.*;
//#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface BusinessObject {
}
*Business Object Name Attribute:
package annotations;
import java.lang.annotation.*;
//#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface BusinessObjectName {
}
I Created a main to test if all the annotations are detected:
public class MainImpl {
public static void main(String[] args) {
// TODO Auto-generated method stub
IndusTask myTask = new IndusTask("mytstTask", "001", "eService Production", "TstTask Process",
"myTstTask Description", "2018/02/16#15:30:10:GMT", 200);
System.out.println(myTask.getClass().getAnnotations().length);
}
}
Output is displaying 1 ! so only the first annotation is detected !
I was told also that the object attributes values can be accessed using these annotation (something similar to) :
object.getClass().getAnnotations()
How can i do ?
You need to iterate through the fields, get their annotations and set the value wherever the annotation matches (it can match multiple fields):
#Retention(RetentionPolicy.RUNTIME)
public #interface Field1 {}
#Retention(RetentionPolicy.RUNTIME)
public #interface Field2 {}
public static class UnderTest {
#Field1
private String field1;
#Field2
private int field2;
public UnderTest(String field1, int field2) {
this.field1 = field1;
this.field2 = field2;
}
#Override
public String toString() {
return field1 + "=" + field2;
}
}
public static void setter(Object obj, Class<? extends Annotation> fieldAnnotation, Object fieldValue) throws IllegalAccessException {
for (Field field: obj.getClass().getDeclaredFields()) {
for (Annotation annot: field.getDeclaredAnnotations()) {
if (annot.annotationType().isAssignableFrom(fieldAnnotation)) {
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(obj, fieldValue);
}
}
}
}
public static void main(String[] argv) throws IllegalAccessException {
UnderTest underTest = new UnderTest("A", 1);
System.out.println(underTest);
setter(underTest, Field1.class, "B");
setter(underTest, Field2.class, 2);
System.out.println(underTest);
}
Running this prints
A=1
B=2
Sounds like you're after the annotations on the fields too?
E.g. for the first private field:
myTask.getClass().getDeclaredFields()[0].getAnnotations()
Note depending how you're accessing a private field, you will sometimes also need to first ensure it is accessible:
...getDeclaredFields()[0].setAccessible(true);
[edit]
The values are reachable too from the fields. A basic worked example:
for (Field f : myTask.getClass().getDeclaredFields()) {
f.setAccessible(true);
System.out.println(f.getName() + "=" + f.get(myTask));
System.out.println(" annotations=" + java.util.Arrays.toString(f.getAnnotations()));
}

Using Bytebuddy to intercept setter

lets asume i have a Interface like that:
public interface User extends Element {
String getName();
String getPassword();
}
and a implementing class like that:
public class BaseUser implements User {
#Override
public String getId() {
return id;
}
#Override
public String getName() {
return name;
}
#Override
public String getPassword() {
return password;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
System.out.println("Set name to " + name);
}
public void setPassword(String password) {
this.password = password;
}
private String id;
private String name;
private String password;
}
Now i want to use bytebuddy to create a interceptor/proxy which catches the call onto the setter, store the changed value and call the real method also.
At the end i want to "ask" the interceptor/proxy for the called setter and the changed values.
I tried a lot considering also the tutorials but up to now i found no working solution. Maybe someone could help me pls.
And here is the Interceptor:
public class GenericInterceptor implements InvocationHandler {
#Override
#RuntimeType
public Object invoke(#This Object proxy, #Origin Method method, #AllArguments Object[] args) throws Throwable {
if (isSetter(method, args)) {
intercept(proxy, method, args);
}
return method.invoke(proxy, args);
}
}
Here is my current 'test' code:
public static void main(String[] args) {
final ByteBuddy bb = new ByteBuddy();
final GenericInterceptor interceptor = new GenericInterceptor();
bb.subclass(BaseUser.class)
.method(isDeclaredBy(BaseUser.class).and(isSetter()))
.intercept(MethodDelegation.to(interceptor))
.make()
.load(BaseUser.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
final BaseUser user = new BaseUser();
user.setName("my name");
}
EDIT:
public interface Element {
String getId();
}
public class GenericInterceptor<T extends Element> {
public GenericInterceptor(Class<T> type) {
this.type = type;
}
public Map<String, Object> getChanges(T obj) {
final String id = obj.getId();
return changes.get(id);
}
#RuntimeType
public void invoke(#This T proxy, #Origin Method method, #AllArguments Object[] args) throws Throwable {
System.out.println("invoke " + method.getName() + " " + Arrays.toString(args));
intercept(proxy, method, args);
}
private Object getCurrentValue(T proxy, final Field field) {
try {
return field.get(proxy);
} catch (IllegalArgumentException | IllegalAccessException e) {
return null;
}
}
private Field getSetterField(Method setter) {
final String setterName = setter.getName();
Field f = assignedFields.get(setterName);
if (f != null) return f;
final String fieldName = Character.toLowerCase(setterName.charAt(3)) + setterName.substring(4);
try {
f = type.getDeclaredField(fieldName);
if (f == null) return null;
f.setAccessible(true);
assignedFields.put(setterName, f);
return f;
} catch (NoSuchFieldException | SecurityException e) {
return null;
}
}
private void intercept(T proxy, Method setter, Object[] args) {
final Field field = getSetterField(setter);
if (field == null)
return;
final Object currentValue = getCurrentValue(proxy, field);
final Object newValue = args[0];
System.out.println("Set from " + currentValue + " to " + newValue);
final String id = proxy.getId();
Map<String, Object> changeMap = changes.get(id);
if (changeMap == null) {
changeMap = new HashMap<>();
}
changeMap.put(field.getName(), currentValue);
changes.put(id, changeMap);
}
private final Map<String, Field> assignedFields = new HashMap<>();
private final Map<String, Map<String, Object>> changes = new LinkedHashMap<>();
private final Class<T> type;
}
You can call orignal method using MethodDelegation.to(...).andThen(SuperMethodCall.INSTANCE).
public class ByteBuddyTest {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
GenericInterceptor interceptor = new GenericInterceptor ();
Class<?> clazz = new ByteBuddy()
.subclass(BaseUser.class)
.method(ElementMatchers.isDeclaredBy(BaseUser.class).and(ElementMatchers.isSetter()))
.intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.to(interceptor))))
.make()
.load(ByteBuddyTest.class.getClassLoader())
.getLoaded();
BaseUser user1 = (BaseUser) clazz.getConstructors()[0].newInstance();
BaseUser user2 = (BaseUser) clazz.getConstructors()[0].newInstance();
user1.setName("user1");
user1.setPassword("password1");
user2.setName("user2");
user2.setPassword("password2");
System.out.println(interceptor.getInterceptedValue("user1", "name"));
System.out.println(interceptor.getInterceptedValue("user1", "password"));
System.out.println(interceptor.getInterceptedValue("user2", "name"));
System.out.println(interceptor.getInterceptedValue("user2", "password"));
user1.setPassword("password2");
user1.setPassword("password3");
}
public static class GenericInterceptor {
private Map<String, Object> interceptedValuesMap = new HashMap();
public void set(String obj, #This User user, #Origin Method setter) {
// assume that user name is unique so we can use it as a key in values map.
// or define equals/hashcode in GenericUser object and use it as a key directly
String setterName = setter.getName();
String propertyName = setterName.substring(3, setterName.length()).toLowerCase();
String key = user.getName() + "_" + propertyName;
System.out.println("Setting " + propertyName + " to " + obj);
System.out.println("Previous value " + interceptedValuesMap.get(key));
interceptedValuesMap.put(key, obj);
}
public Object getInterceptedValue(String userName, String fieldName) {
return interceptedValuesMap.get(userName + "_" + fieldName);
}
}
public static interface User {
String getName();
String getPassword();
}
public static class BaseUser implements User {
#Override
public String getName() {
return name;
}
#Override
public String getPassword() {
return password;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
private String name;
private String password;
}
}

JaxB Unmarshalling attributes into a hashmap

I have the following XML:
<object>
<name>Test</name>
<bikes>
<bike key="Hello" value="World"/>
</bikes>
</object>
So I then have the following Objects:
#XmlRootElement
public class Object {
#XmlElement
private String name;
#XmlElement
private Bikes bikes;
public Object(String name, Bikes bikes) {
this.name = name;
this.bikes = bikes;
}
Bikes
public class Bikes{
private Map<String, String> bike = new HashMap();
#XmlElement
public Bikes(Map<String, String> bike) {
this.bike = bike;
}
I have tried to unmarshall the xml into the the above classes but I am not sure how.
Found a couple of answers on here but none seemed to work as I needed.
You shall be able to do it using adapter class. here is a working case.
Object.java
The class has XmlJavaTypeAdapter(BikeAdapter.class) annoted to bikes map. Adapter and wrapper class are defined here itself.
package testjaxb;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Object {
#XmlElement
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, String> getBikes() {
return bikes;
}
public void setBikes(Map<String, String> bikes) {
this.bikes = bikes;
}
#XmlJavaTypeAdapter(BikeAdapter.class)
private Map<String, String> bikes;
public Object() {
}
}
class BikeWrapper {
#XmlElement(name = "bike")
List<Bike> bike = new ArrayList<Bike>();
}
class BikeAdapter extends XmlAdapter<BikeWrapper, Map<String, String>> {
public BikeWrapper marshal(Map<String, String> arg0) throws Exception {
BikeWrapper bw = new BikeWrapper();
List<Bike> bikes = new ArrayList<Bike>();
for (Map.Entry<String, String> entry : arg0.entrySet()) {
bikes.add(new Bike(entry.getKey(), entry.getValue()));
}
bw.bike = bikes;
return bw;
}
public Map<String, String> unmarshal(BikeWrapper arg0) throws Exception {
Map<String, String> r = new HashMap<String, String>();
for (Bike mapelement : arg0.bike) {
r.put(mapelement.getKey(), mapelement.getValue());
}
return r;
}
}
Bike.jaa
package testjaxb;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
#XmlAccessorType(XmlAccessType.FIELD)
public class Bike {
#XmlAttribute()
private String key;
public Bike() {
}
public Bike(String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#XmlAttribute()
private String value;
public String toString() {
return "Bike : key-" + getKey() + ", value -" + getValue();
}
}
And here is your Main class to test.
package testjaxb;
import java.io.StringReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
public class Main {
public static void main(String[] args) throws Exception {
String xmlString = "<object>\n"
+ " <name>Test</name>\n"
+ " <bikes>\n"
+ " <bike key=\"Hello\" value=\"World\"/>\n"
+ " </bikes>\n"
+ "</object>";
testjaxb.Object o = unmarshal(testjaxb.Object.class, xmlString);
System.out.println("Bike List.." + o.getBikes());
}
private static <C> C unmarshal(Class<C> c, String sampleXML) throws Exception {
JAXBContext jc = JAXBContext.newInstance(c);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StringReader reader = new StringReader(sampleXML);
//System.out.println("" + sampleXML);
return (C) unmarshaller.unmarshal(reader);
}
}

java getMethod() on generic type

i want use reflection on generic type
i have this class
package it.ciro.service;
import it.ciro.dao.SysMyAbDao;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Created by ciro on 09/12/2016.
*/
public class SelectOption<E extends Serializable> {
private SysMyAbDao dao;
private Class<E> entity;
private ArrayList<Class<E>> entityAll;
private Map<String,String> optionList = new HashMap<String,String>();
protected Logger logger;
public SelectOption(SysMyAbDao dao,Class<E> entity,String idName, String labelName ){
logger = Logger.getLogger(this.getClass());
this.dao = dao;
this.entity = entity;
entityAll = dao.findAll();
try{
Method idMethod = this.entity.getMethod(idName);
Method labelMethod = this.entity.getClass().getMethod(labelName);
for (Class<E> single : entityAll) {
optionList.put((String)idMethod.invoke(single),(String)labelMethod.invoke(single));
}
}catch (NoSuchMethodException ex){
ex.printStackTrace();
logger.error(ex.getMessage());
} catch (InvocationTargetException e) {
logger.error(e.getMessage());
} catch (IllegalAccessException e) {
logger.error(e.getMessage());
}
}
public Map<String, String> getOptionList() {
return optionList;
}
}
and in my controller
SelectOption<GeoProvince> selectOption = new SelectOption(geoRegionDao,GeoRegion.class,"idGeoRegion","name");
but i get
java.lang.NoSuchMethodException: java.lang.Class.idGeoRegion()
java search on generic type e not on type that I use in constructor
I expect the search to be made about the type I spend in controller. In GeoRegion class the method exists.
this is SysMyAbDao
public abstract class SysMyAbDao<T, E, Id extends Serializable> {
protected String message;
protected Boolean status;
protected T t ;
protected Logger logger;
protected Long totalRow;
private Class<T> type;
public SysMyAbDao(Class<T> type){
this.type = type;
}
.....
GeoRegion class
public class GeoRegion implements java.io.Serializable {
private int idRegion;
private String name;
private String code;
private Set<GeoProvince> geoProvinces = new HashSet<GeoProvince>(0);
private Set<GeoCity> geoCities = new HashSet<GeoCity>(0);
public GeoRegion() {
}
public GeoRegion(int idRegion) {
this.idRegion = idRegion;
}
public GeoRegion(int idRegion, String name, String code, Set<GeoProvince> geoProvinces, Set<GeoCity> geoCities) {
this.idRegion = idRegion;
this.name = name;
this.code = code;
this.geoProvinces = geoProvinces;
this.geoCities = geoCities;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id_region", unique=true, nullable=false)
public int getIdRegion() {
return this.idRegion;
}
public void setIdRegion(int idRegion) {
this.idRegion = idRegion;
}
#Column(name="name")
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#Column(name="code", unique=true)
public String getCode() {
return this.code;
}
public void setCode(String code) {
this.code = code;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="geoRegion")
public Set<GeoProvince> getGeoProvinces() {
return this.geoProvinces;
}
public void setGeoProvinces(Set<GeoProvince> geoProvinces) {
this.geoProvinces = geoProvinces;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="geoRegion")
public Set<GeoCity> getGeoCities() {
return this.geoCities;
}
public void setGeoCities(Set<GeoCity> geoCities) {
this.geoCities = geoCities;
}
}
You have an extra getClass() in this line:
Method labelMethod = this.entity.getClass().getMethod(labelName);
In fact, you are calling getClass() on the Class<E> object. And as the class of Class<E> is not E but java.lang.Class you get the NoSuchMethodException you posted.
Also the instance which you are invoking your method on (single in your case), should be of type E and not of type Class<E>.
Overall you would end up with something like:
public SelectOption(SysMyAbDao<E, ?, ? extends Serializable> dao,
Class<E> entityClass,
String idName,
String labelName) {
this.dao = dao;
this.entityClass = entityClass;
this.entityAll = dao.findAll(); // make sure your SysMyAbDao<E, ?, ?>#findAll() returns a Collection<E>
try{
Method idMethod = this.entityClass.getMethod(idName);
Method labelMethod = this.entityClass.getMethod(labelName);
for (E instance : entityAll) {
optionList.put((String)idMethod.invoke(instance),(String)labelMethod.invoke(instance));
}
} catch (NoSuchMethodException ex){
...
}
}
You are trying to invoke your method on single, which is a Class object.
I don't see any instances of GeoRegion in this code. But in order for this to work, you need to use this method on one of them:
E instance = getSomeObjectFromSomewhere();
optionList.put((String)idMethod.invoke(instance),(String)labelMethod.invoke(instance));

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