Jackson Conditional Validation of a field - java

I'm trying to set up a Range Query structure on Spring with the following structure:
public class QueryRange extends Query {
#JsonProperty(required = true)
#NotBlank
#NotNull
private String field;
private Object gt;
private Object gte;
private Object lt;
private Object lte;
public String getField() {
return field;
}
public QueryRange setField(String field) {
this.field = field;
return this;
}
public Object getGt() {
return gt;
}
public QueryRange setGt(Object gt) {
this.gt = gt;
return this;
}
public Object getGte() {
return gte;
}
public QueryRange setGte(Object gte) {
this.gte = gte;
return this;
}
public Object getLt() {
return lt;
}
public QueryRange setLt(Object lt) {
this.lt = lt;
return this;
}
public Object getLte() {
return lte;
}
public QueryRange setLte(Object lte) {
this.lte = lte;
return this;
}
#AssertTrue(message = "Invalid range. A value for 'gt' or 'lt' should be set.")
private boolean isRangeSpecified() {
return this.gt != null || this.lt != null;
}
#AssertTrue(message = "Invalid range data type. 'gt' and 'lt' must be of the same type.")
private boolean isRangeDataTypeValid() {
if (this.gt != null && this.lt != null) {
return this.gt.getClass().equals(this.lt.getClass());
}
return true;
}
}
The problem is that at least one of the values gt, gte, lt or lte should be not null. How can I validate that?
I've tried Bean Validation like on the code example above, but it didn't work. Any suggestions?

You should use Class-level constraint.
Last but not least, a constraint can also be placed on the class level. In this case not a single property is subject of the validation but the complete object. Class-level constraints are useful if the validation depends on a correlation between several properties of an object.
#ValidQueryRange
public class QueryRange extends Query {
// your class here...
private Object gt;
private Object gte;
private Object lt;
private Object lte;
}
#Target({ TYPE, ANNOTATION_TYPE })
#Retention(RUNTIME)
#Constraint(validatedBy = { ValidQueryRangeValidator.class })
#Documented
public #interface ValidQueryRange {
String message() default "{error}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
public class ValidQueryRangeValidator implements ConstraintValidator<ValidQueryRange, QueryRange> {
#Override
public void initialize(ValidQueryRange constraintAnnotation) {
}
#Override
public boolean isValid(QueryRange queryRange, ConstraintValidatorContext context) {
if ( queryRange == null ) {
return true;
}
// put your logic here
if ( queryRange.getGt() == null || queryRange.getLt() == null) {
return false;
}
return true;
}
}

Related

Custom Jackson Deserialization of a Generic Abstract class

I am having issues when trying to deserializing the following class:
public class MetricValuesDto {
private Map<MetricType, MetricValueDto<?>> metricValues;
public MetricValuesDto() {
}
public MetricValuesDto(Map<MetricType, MetricValueDto<?>> metricValues) {
this.metricValues = metricValues;
}
public Map<MetricType, MetricValueDto<?>> getMetricValues() {
return metricValues;
}
public void setMetricValues(Map<MetricType, MetricValueDto<?>> metricValues) {
this.metricValues = metricValues;
}
}
My generic abstract class:
public abstract class MetricValueDto<T> {
private T value;
private MetricTrend trend;
public MetricValueDto(T value, MetricTrend trend) {
this.value = value;
this.trend = trend;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
public MetricTrend getTrend() {
return trend;
}
public void setTrend(MetricTrend trend) {
this.trend = trend;
}
}
I have two concrete classes which implement MetricValueDto:
IntMetricValueDto:
public class IntMetricValueDto extends MetricValueDto<Integer> {
public IntMetricValueDto(Integer value, MetricTrend trend) {
super(value, trend);
}
}
FloatMetricValueDto:
public class FloatMetricValueDto extends MetricValueDto<Float> {
public FloatMetricValueDto(Float value, MetricTrend trend) {
super(value, trend);
}
}
Any idea of what's the correct strategy to deserialize MetricValueDto so I can parse it through ObjectMapper or an RestTemplate? Whenever I run:
restTemplate.exchange("myEndpoint", HttpMethod.GET, entity, DataCollectionEventDto.class);
I get
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.resson.dto.MetricValueDto: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
DataCollectionEventDto:
public class DataCollectionEventDto {
private List<MapLayerDto> mapLayers;
#JsonUnwrapped
private MetricValuesDto metricValues;
public List<MapLayerDto> getMapLayers() {
return mapLayers;
}
public void setMapLayers(List<MapLayerDto> mapLayers) {
this.mapLayers = mapLayers;
}
public MetricValuesDto getMetricValues() {
return metricValues;
}
public void setMetricValues(MetricValuesDto metricValues) {
this.metricValues = metricValues;
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}
I have basically tried everything on web and I could not make it work; any suggestion would be helpful.
Use JsonSubTypes annotation with JsonTypeInfo to indicate subtypes. The property attribute JsonTypeInfo is used to differentiate between different subclasses.
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "typ")
#JsonSubTypes({
#JsonSubTypes.Type(value = IntMetricValueDto.class, name = "INT"),
#JsonSubTypes.Type(value = FloatMetricValueDto.class, name = "FLT")})
public abstract class MetricValueDto<T> {
private T value;
private MetricTrend trend;
...
}
While JsonTypeInfo works, and adds implementation-specific detail to the response, which later might add confusion to the API client.
I ended up implementing a custom StdDeserializer:
public class MetricValueDtoDeserializer<T> extends StdDeserializer<MetricValueDto<T>> {
private static final long serialVersionUID = 1L;
public MetricValueDtoDeserializer() {
this(null);
}
public MetricValueDtoDeserializer(Class<?> vc) {
super(vc);
}
private ObjectMapper mapper;
#Override
public MetricValueDto<T> deserialize(JsonParser jsonParser, DeserializationContext context)
throws IOException, JsonProcessingException {
String metricType = jsonParser.getCurrentName();
mapper = (ObjectMapper) jsonParser.getCodec();
ObjectNode objectNode = (ObjectNode) mapper.readTree(jsonParser);
Iterator<Entry<String, JsonNode>> elementsIterator = objectNode.fields();
Number number = null;
while (elementsIterator.hasNext()) {
Entry<String, JsonNode> element = elementsIterator.next();
String key = element.getKey();
if (key.equals("value")) {
number = parseValue(element, metricType);
}
if (key.equals("trend")) {
MetricTrend metricTrend = parseTrend(element);
return (produceMetricValueDto(number, metricTrend));
}
}
throw new IOException();
}
#SuppressWarnings("unchecked")
private MetricValueDto<T> produceMetricValueDto(Number number, MetricTrend metricTrend) throws IOException {
if (number instanceof Integer) {
return (MetricValueDto<T>) new IntMetricValueDto((Integer) number, metricTrend);
} else if (number instanceof Float) {
return (MetricValueDto<T>) new FloatMetricValueDto((Float) number, metricTrend);
}
throw new IOException();
}
private MetricTrend parseTrend(Entry<String, JsonNode> element)
throws JsonProcessingException {
String trend = mapper.treeToValue(element.getValue(), String.class);
if (trend == null) {
return null;
} else {
return MetricTrend.valueOf(trend);
}
}
private Number parseValue(Entry<String, JsonNode> element, String metricType)
throws IOException {
if (metricType.equals(MetricType.CANOPY_COVERAGE.toValue())
|| metricType.equals(MetricType.PLANT_SIZE.toValue())) {
return mapper.treeToValue(element.getValue(), Float.class);
} else if (metricType.equals(MetricType.INSECT_COUNT.toValue())
|| metricType.equals(MetricType.PLANT_COUNT.toValue())) {
return mapper.treeToValue(element.getValue(), Integer.class);
}
throw new IOException();
}
}
The code ended up to being more complex than JsonTypeInfo, but the API client is unaware of implementation-specific details.

How to solve StringConverter ClassCast Exception?

I have a TableView and a form with some TextBox and ComboBox in my javafx application. I am trying to populate the form components with selected rows data from TableView. I can populate all the TextBox without any error or exception. But while setting values to ComboBoxes, it's throwing an ClassCastException, java.lang.ClassCastException: java.lang.String cannot be cast to entity.StockUOM.
This is my StringCoverter
unitCombo.setConverter(new StringConverter<StockUOM>() {
#Override
public String toString(StockUOM object) {
return object.getStockUOM();
}
#Override
public StockUOM fromString(String string) {
return null;
}
});
This is my entity.StockUOM class
#Entity
#Access(AccessType.PROPERTY)
#NamedQueries({
#NamedQuery(name = StockUOM.findStockUOM, query = "SELECT s from StockUOM s")
})
public class StockUOM implements Externalizable{
public final static String PREFIX = "entity.StockUOM.";
public final static String findStockUOM = PREFIX + "findStockUOM";
private IntegerProperty id;
private int _id;
private StringProperty stockUOM;
private String _stockUOM;
public StockUOM() {
if (id == null) {
id = new SimpleIntegerProperty(this, "id", _id);
}
if( stockUOM== null){
stockUOM= new SimpleStringProperty(this,"stockUOM",_stockUOM);
}
}
public StockUOM(String stockUOM) {
this();
this.stockUOM.set(stockUOM);
}
public IntegerProperty idProperty() {
if (id == null) {
id = new SimpleIntegerProperty(this, "id", _id);;
}
return id;
}
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public final int getId() {
if (id == null) {
return _id;
} else {
return id.get();
}
}
public final void setId(int id) {
if (this.id == null) {
_id = id;
} else {
this.id.set(id);
}
}
public StringProperty stockUOMProperty() {
if( stockUOM== null){
stockUOM= new SimpleStringProperty(this,"stockUOM",_stockUOM);
}
return stockUOM;
}
public final String getStockUOM() {
if(stockUOM == null){
return _stockUOM;
}else{
return stockUOM.get();
}
}
public void setStockUOM(String stockUOM) {
if (this.stockUOM == null) {
_stockUOM=stockUOM ;
} else {
this.stockUOM.set(stockUOM);
}
}
#Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(getId());
out.writeChars(getStockUOM());
}
#Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
setId(in.readInt());
setStockUOM((String)in.readObject());
}
#Override
public String toString() {
return getStockUOM();
}
}
This is how i am setting values to ComboBox
unitCombo.setValue(newValue.getUnit());
Here newValue is the instance of StockUOM of ChangeListner which is listening on TableView row selection.
So what's wrong i am doing ? And what's the solution.
Thanks.
The problem is that most probably you defined your ComboBox like:
ComboBox unitCombo = new ComboBox();
So you missed to define the generic argument and you ended up with the raw type (your IDE most probably gives you a warning on this line).
At this point it is not specified what kind of objects do you want to display in the ComboBox.
When you do the following:
unitCombo.setValue(newValue.getUnit());
you set the valueProperty as a String value.
And then comes your converter:
unitCombo.setConverter(new StringConverter<StockUOM>() {
#Override
public String toString(StockUOM object) {
return object.getStockUOM();
}
#Override
public StockUOM fromString(String string) {
return null;
}
});
which expects StockUOM object being displayed, which does not happen hence the error.
You have to decide what kind of object do you want to display: if it is StockUOM, then declare the ComboBox as ComboBox<StockUOM> unitCombo = new ComboBox<StockUOM>();. After this you will have a compile time error on the line where you set the value for a String value, to fix that error you have to modify that line as unitCombo.setValue(newValue);. If you want to display String objects, the methodology is the same.

Guice Multibinder for Annotations with Specific Value

I know that I can do a Guice multibind with a specific annotation as follows
Multibinder.newSetBinder(binder(), Bound.class, Annotation.class);
But can I do a more specific multibind on classes that are not only annotated with Annotation.class but also have a specific value, e.g. #Annotation("type1")?
In this case you could implement your annotation and pass an instance of it to the Multibinder static factory method:
static class YourAnnotationImpl implements YourAnnotation {
private final String value;
YourAnnotationImpl(String value) {
this.value = value;
}
#Override public String value() {
return value;
}
#Override public Class<? extends Annotation> annotationType() {
return YourAnnotation.class;
}
#Override public String toString() {
return "#" + YourAnnotation.class.getName() + "(value=" + value + ")";
}
#Override public boolean equals(Object o) {
return o instanceof YourAnnotationImpl
&& ((YourAnnotationImpl) o).value().equals(value());
}
#Override public int hashCode() {
return (127 * "value".hashCode()) ^ value.hashCode();
}
}
...
Multibinder.newSetBinder(binder(), Bound.class, new YourAnnotationImpl("type1");

How to map custom enumerated integer ordinals with hibernate?

I have an enum class named Status as follows
public enum Status {
PENDING(0), SUCCESS(1), FAILED(-1);
private int st;
private Status(int st){
this.st = st;
}
}
and from other class I try to map this status enum
public void setStatus(Status status) {
this.status = status;
}
#Enumerated(EnumType.ORDINAL)
public Status getStatus() {
return status;
}
when I run this code, I get
java.lang.IllegalArgumentException: Unknown ordinal value for enum class data.Status: -1
at org.hibernate.type.EnumType.nullSafeGet(EnumType.java:93)
at org.hibernate.type.CustomType.nullSafeGet(CustomType.java:124)
at org.hibernate.type.AbstractType.hydrate(AbstractType.java:106)
at
but I already have -1 in enum definition.
You could define your own UserType which defines how Hibernate should map those enums.
Note that the ordinal defines the index of the enum value and thus FAILED would have the ordinal 2. To map the enum using its properties your need a UserType implementation.
Some links:
https://community.jboss.org/wiki/UserTypeForPersistingAnEnumWithAVARCHARColumn
http://javadata.blogspot.de/2011/07/hibernate-and-enum-handling.html (look at the "Paramterized Enumeration in Hibernate" section)
Here is a solution where a string label is used instead of an int id, however it is simple to adapt.
public class User {
#Id
private int id;
#Type(type = "com.example.hibernate.LabeledEnumType")
private Role role;
}
public enum Role implements LabeledEnum {
ADMIN("admin"), USER("user"), ANONYMOUS("anon");
private final String label;
Role(String label) {
this.label = label;
}
#Override
public String getLabel() {
return label;
}
}
public interface LabeledEnum {
String getLabel();
}
public final class LabeledEnumType implements DynamicParameterizedType, UserType {
private Class<? extends Enum> enumClass;
#Override
public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return cached;
}
#Override
public Object deepCopy(Object value) throws HibernateException {
return value;
}
#Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
#Override
public boolean equals(Object x, Object y) throws HibernateException {
return x == y;
}
#Override
public int hashCode(Object x) throws HibernateException {
return x == null ? 0 : x.hashCode();
}
#Override
public boolean isMutable() {
return false;
}
#Override
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
String label = rs.getString(names[0]);
if (rs.wasNull()) {
return null;
}
for (Enum value : returnedClass().getEnumConstants()) {
if (value instanceof LabeledEnum) {
LabeledEnum labeledEnum = (LabeledEnum) value;
if (labeledEnum.getLabel().equals(label)) {
return value;
}
}
}
throw new IllegalStateException("Unknown " + returnedClass().getSimpleName() + " label");
}
#Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
if (value == null) {
st.setNull(index, Types.VARCHAR);
} else {
st.setString(index, ((LabeledEnum) value).getLabel());
}
}
#Override
public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return original;
}
#Override
public Class<? extends Enum> returnedClass() {
return enumClass;
}
#Override
public int[] sqlTypes() {
return new int[]{Types.VARCHAR};
}
#Override
public void setParameterValues(Properties parameters) {
ParameterType params = (ParameterType) parameters.get( PARAMETER_TYPE );
enumClass = params.getReturnedClass();
}
}
I would like to suggest following workaround. At first I was supprised it worked but it is really simple:
For enum:
public enum Status {
PENDING(0), SUCCESS(1), FAILED(-1);
private int status;
private Status(int status){
this.status = status;
}
public String getStatus() {
return status;
}
public static Status parse(int id) {
Status status = null; // Default
for (Status item : Status.values()) {
if (item.getStatus().equals(id)) {
Status = item;
break;
}
}
return Status;
}
}
class
class StatedObject{
#Column("status")
private int statusInt;
public Status getStatus() {
return Status.parse(statusInt);
}
public void setStatus(Status paymentStatus) {
this.statusInt = paymentStatus.getStatus();
}
public String getStatusInt() {
return statusInt;
}
public void setStatusInt(int statusInt) {
this.statusInt = statusInt;
}
}
if you are using hibernate in hibernate xml file it would be:
<property name="statusInt " column="status" type="java.lang.Integer" />
that is it

Can't Marshal java.lang.String

Here is my dilemma:
I have a dto class for marshaling back and forth from/to XML.
Here is the trick: Because of the number of dto classes our project deals with that are collections with a plural outter tag, I decided to create a delegate collection that allows me to take one of these classes and effortlessly turn them into a Collection and get the convenience that comes with it (iteration, add, etc.).
In our project we have marshaling tests to flush out annotation errors and such.
Below is my trouble code.
Problem:
Depending on the marshaler, if I extend this QuickCollection I get the below error.
When the object is unmarshaled to xml using CXF as a response to a webservice request, it fails. Exact error:
com.sun.istack.SAXException2: unable to marshal type "java.lang.String" as an element because it is missing an #XmlRootElement annotation
When it's marshaled/unmarshaled with JAXB in test it's fine.
When This same QuickCollection is used to marshal in results from 3rd parties using spring RestOperations and works fine
the mind screw:
When I remove the inheritance and manage the collection as a private member it all just works!
This makes not a stitch of sense to me as I am literally returning the exact data type in both situations.
Below is all relevant code.
This is the Inherited delegate class.
public class QuickCollection<T> implements Collection<T> {
// to be set if needed after instantiation. To behave like a normal collection, we set it to something safe
protected Collection<T> delegate = Collections.emptySet();
public QuickCollection() {
}
public QuickCollection(Collection<T> delegate) {
this.delegate = delegate;
}
#Override
public int size() {
return delegate.size();
}
#Override
public boolean isEmpty() {
return delegate.isEmpty();
}
#Override
public boolean contains(Object o) {
return delegate.contains(o);
}
#Override
public Iterator<T> iterator() {
return delegate.iterator();
}
#Override
public Object[] toArray() {
return delegate.toArray();
}
#Override
public <T> T[] toArray(T[] a) {
return delegate.toArray(a);
}
#Override
public boolean add(T t) {
return delegate.add(t);
}
#Override
public boolean remove(Object o) {
return delegate.remove(o);
}
#Override
public boolean containsAll(Collection<?> c) {
return delegate.containsAll(c);
}
#Override
public boolean addAll(Collection<? extends T> c) {
return delegate.addAll(c);
}
#Override
public boolean removeAll(Collection<?> c) {
return delegate.removeAll(c);
}
#Override
public boolean retainAll(Collection<?> c) {
return delegate.retainAll(c);
}
#Override
public void clear() {
delegate.clear();
}
#Override
public String toString() {
return "" + delegate.toString();
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
QuickCollection that = (QuickCollection) o;
if (delegate != null ? !delegate.equals(that.delegate) : that.delegate != null) return false;
return true;
}
#Override
public int hashCode() {
return delegate != null ? delegate.hashCode() : 0;
}
}
Here is the child DTO class
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlType(name = "BuddyCodes")
#XmlRootElement(name = "BuddyCodes")
public class BuddyCodes extends QuickCollection<String> implements Xml {
private Long accountId;
private Date expirationDate;
public BuddyCodes() {
super.delegate = new HashSet<String>();
}
public BuddyCodes(Long accountId, Set<String> codes, Date expirationDate) {
super(codes);
this.accountId = accountId;
this.expirationDate = expirationDate;
super.delegate = new HashSet<String>();
}
public BuddyCodes(Long accountId, Date expirationDate) {
this.accountId = accountId;
this.expirationDate = expirationDate;
super.delegate = new HashSet<String>();
}
#Override
public String toXml() {
String retVal;
try {
retVal = StringUtils.toXml(this);
}
catch (JAXBException e) {
retVal = e.toString();
}
return retVal;
}
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public Set<String> getCodes() {
return (Set<String>) super.delegate;
}
#XmlElement(name = "code")
public void setCodes(Set<String> codes) {
super.delegate = codes;
}
public Date getExpirationDate() {
return expirationDate;
}
public void setExpirationDate(Date expirationDate) {
this.expirationDate = expirationDate;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BuddyCodes that = (BuddyCodes) o;
if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) return false;
if (delegate != null ? !super.delegate.equals(that.delegate) : that.delegate != null) return false;
if (expirationDate != null ? !expirationDate.equals(that.expirationDate) : that.expirationDate != null)
return false;
return true;
}
#Override
public int hashCode() {
int result = accountId != null ? accountId.hashCode() : 0;
result = 31 * result + (expirationDate != null ? expirationDate.hashCode() : 0);
result = 31 * result + (super.delegate != null ? super.delegate.hashCode() : 0);
return result;
}
#Override
public String toString() {
return "BuddyCodes{" +
"accountId=" + accountId +
"codes=" + super.delegate +
", expirationDate=" + expirationDate +
'}';
}
}
And it doesn't work. I get the error.
Now, here is the child class after removing the inheritance and it works!!!
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.*;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
/**
* #author christian.bongiorno
* Date: 10/3/11
* Time: 6:11 PM
*/
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlType(name = "BuddyCodes")
#XmlRootElement(name = "BuddyCodes")
public class BuddyCodes implements Xml {
private Long accountId;
private Date expirationDate;
private Set<String> delegate;
public BuddyCodes() {
delegate = new HashSet<String>();
}
public BuddyCodes(Long accountId, Set<String> codes, Date expirationDate) {
this.accountId = accountId;
this.expirationDate = expirationDate;
delegate = new HashSet<String>();
}
public BuddyCodes(Long accountId, Date expirationDate) {
this.accountId = accountId;
this.expirationDate = expirationDate;
delegate = new HashSet<String>();
}
#Override
public String toXml() {
String retVal;
try {
retVal = StringUtils.toXml(this);
}
catch (JAXBException e) {
retVal = e.toString();
}
return retVal;
}
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public Set<String> getCodes() {
return delegate;
}
#XmlElement(name = "code")
public void setCodes(Set<String> codes) {
delegate = codes;
}
public Date getExpirationDate() {
return expirationDate;
}
public void setExpirationDate(Date expirationDate) {
this.expirationDate = expirationDate;
}
public boolean add(String s) {
return delegate.add(s);
}
public int size() {
return delegate.size();
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BuddyCodes that = (BuddyCodes) o;
if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) return false;
if (delegate != null ? !delegate.equals(that.delegate) : that.delegate != null) return false;
if (expirationDate != null ? !expirationDate.equals(that.expirationDate) : that.expirationDate != null)
return false;
return true;
}
#Override
public int hashCode() {
int result = accountId != null ? accountId.hashCode() : 0;
result = 31 * result + (expirationDate != null ? expirationDate.hashCode() : 0);
result = 31 * result + (delegate != null ? delegate.hashCode() : 0);
return result;
}
}
Why does the inheritance matter at all???
I haven't figured this out but, I have another DTO in a similar layout (BuddyTypes BuddyType). BuddyType has 2 members: Long and String. Both are annoted as XmlElement. This one works just fine.
It seems the problem that the members of the set making up the delegate are not annotated in my problem case and I don't know how to annotate a parent member. As an inherited class, it wouldn't make sense to have some sort of default name/annotation. But, I tried this madness and the annotation is ignored -- I have seen parent member annotations ignored before so this isn't new.
I don't know if it's possible, but I need to annotate a parent member.
A bit out of the box: try Simple XML library instead of JAXB. My experience with it is the best.

Categories