Jackson won't deserialize on org.immutable interface - java

Following scenario.
Little SpringBoot application with the following classes:
FooDto:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.util.LinkedList;
import java.util.List;
import org.immutables.value.Value;
#Value.Immutable
#JsonDeserialize(builder = FooDto.Builder.class)
public interface FooDto{
#JsonProperty("fee")
String getFee();
#JsonProperty("fii")
String getFii();
#JsonProperty("url")
String getUrl();
#Value.Default
#JsonProperty("values")
default String[] getValues(){
return new String[0];
}
}
FooJsonMapper:
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.springframework.stereotype.Component;
#Component
/*package*/ class FooJsonMapper {
private final ObjectMapper objectMapper;
FooJsonMapper() {
objectMapper = new ObjectMapper();
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES);
}
public List<FooDto> toDtos(File jsonFile) throws IOException {
return Arrays.asList(objectMapper.readValue(jsonFile, FooDto[].class));
}
}
and a JSON like this:
[
{
"fee":"SOME_MESSAGE",
"fii":"SOME_TECH_MESSAGE",
"url":"/some",
"values":[
"test",
"some"
]
},
{
"fee":"OTHER_MESSAGE",
"fii":"OTHER_TECH_MESSAGE",
"url":"/other",
"values":[
"other",
"some"
]
},
{
"fee":"4711_MESSAGE",
"fii":"4711_TECH_MESSAGE",
"url":"/4711",
"values":[
]
}
]
Somehow when running the code jackson reports the following:
com.fasterxml.jackson.databind.exc.ValueInstantiationException: Cannot construct instance of `org.some.package.ImmutableFooDto$Builder`, problem: Cannot build FooDto, some of required attributes are not set [fee, fii, url]
at [Source: (File); line: 13, column: 3] (through reference chain: java.lang.Object[][0])
at com.fasterxml.jackson.databind.exc.ValueInstantiationException.from(ValueInstantiationException.java:47) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1907) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.DeserializationContext.handleInstantiationProblem(DeserializationContext.java:1260) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapInstantiationProblem(BeanDeserializerBase.java:1865) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.finishBuild(BuilderBasedDeserializer.java:202) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.deserialize(BuilderBasedDeserializer.java:217) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:214) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:24) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4593) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3413) ~[jackson-databind-2.12.3.jar:2.12.3]
at org.some.package.FooJsonMapper.toDtos(FooJsonMapper.java:25) ~[classes/:na]
I can confirm that the json is correct as the following line of code creates Objects with the data in them:
return Arrays.asList(objectMapper.readValue(jsonFile, Object[].class));
I also tried using #Value.Style(builder = "new") at the FooDto.class as sugested here: https://immutables.github.io/json.html
Jackson: 2.12.3
org.immutables: 2.8.2
EDIT:
As Requested the ImmutableDTO with Builder:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import javax.annotation.Generated;
/**
* Immutable implementation of {#link FooDto}.
* <p>
* Use the builder to create immutable instances:
* {#code ImmutableFooDto.builder()}.
*/
#SuppressWarnings("all")
#Generated({"Immutables.generator", "FooDto"})
public final class ImmutableFooDto implements FooDto {
private final String fee;
private final String fii;
private final String url;
private final String[] values;
private ImmutableFooDto(ImmutableFooDto.Builder builder) {
this.fee = builder.fee;
this.fii = builder.fii;
this.url = builder.url;
if (builder.values != null) {
initShim.values(builder.values);
}
this.values = initShim.getValues();
this.initShim = null;
}
private ImmutableFooDto(
String fee,
String fii,
String url,
String[] values) {
this.fee = fee;
this.fii = fii;
this.url = url;
this.values = values;
this.initShim = null;
}
private static final int STAGE_INITIALIZING = -1;
private static final int STAGE_UNINITIALIZED = 0;
private static final int STAGE_INITIALIZED = 1;
private transient volatile InitShim initShim = new InitShim();
private final class InitShim {
private String[] values;
private int valuesStage;
String[] getValues() {
if (valuesStage == STAGE_INITIALIZING) throw new IllegalStateException(formatInitCycleMessage());
if (valuesStage == STAGE_UNINITIALIZED) {
valuesStage = STAGE_INITIALIZING;
this.values = getValuesInitialize().clone();
valuesStage = STAGE_INITIALIZED;
}
return this.values;
}
void values(String[] values) {
this.values = values;
valuesStage = STAGE_INITIALIZED;
}
private String formatInitCycleMessage() {
ArrayList<String> attributes = new ArrayList<String>();
if (valuesStage == STAGE_INITIALIZING) attributes.add("values");
return "Cannot build FooDto, attribute initializers form cycle" + attributes;
}
}
private String[] getValuesInitialize() {
return FooDto.super.getValues();
}
/**
* #return The value of the {#code fee} attribute
*/
#JsonProperty("fee")
#Override
public String getFee() {
return fee;
}
/**
* #return The value of the {#code fii} attribute
*/
#JsonProperty("fii")
#Override
public String getFii() {
return fii;
}
/**
* #return The value of the {#code url} attribute
*/
#JsonProperty("url")
#Override
public String getUrl() {
return url;
}
/**
* #return A cloned {#code values} array
*/
#JsonProperty("values")
#Override
public String[] getValues() {
InitShim shim = this.initShim;
return shim != null
? shim.getValues().clone()
: this.values.clone();
}
/**
* Copy the current immutable object by setting a value for the {#link FooDto#getFee() fee} attribute.
* An equals check used to prevent copying of the same value by returning {#code this}.
* #param fee A new value for fee
* #return A modified copy of the {#code this} object
*/
public final ImmutableFooDto withFee(String fee) {
if (this.fee.equals(fee)) return this;
String newValue = Objects.requireNonNull(fee, "fee");
return new ImmutableFooDto(newValue, this.fii, this.url, this.values);
}
/**
* Copy the current immutable object by setting a value for the {#link FooDto#getFii() fii} attribute.
* An equals check used to prevent copying of the same value by returning {#code this}.
* #param fii A new value for fii
* #return A modified copy of the {#code this} object
*/
public final ImmutableFooDto withFii(String fii) {
if (this.fii.equals(fii)) return this;
String newValue = Objects.requireNonNull(fii, "fii");
return new ImmutableFooDto(this.fee, newValue, this.url, this.values);
}
/**
* Copy the current immutable object by setting a value for the {#link FooDto#getUrl() url} attribute.
* An equals check used to prevent copying of the same value by returning {#code this}.
* #param url A new value for url
* #return A modified copy of the {#code this} object
*/
public final ImmutableFooDto withUrl(String url) {
if (this.url.equals(url)) return this;
String newValue = Objects.requireNonNull(url, "url");
return new ImmutableFooDto(this.fee, this.fii, newValue, this.values);
}
/**
* Copy the current immutable object with elements that replace the content of {#link FooDto#getValues() values}.
* The array is cloned before being saved as attribute values.
* #param elements The non-null elements for values
* #return A modified copy of {#code this} object
*/
public final ImmutableFooDto withValues(String... elements) {
String[] newValue = elements.clone();
return new ImmutableFooDto(this.fee, this.fii, this.url, newValue);
}
/**
* This instance is equal to all instances of {#code ImmutableFooDto} that have equal attribute values.
* #return {#code true} if {#code this} is equal to {#code another} instance
*/
#Override
public boolean equals(Object another) {
if (this == another) return true;
return another instanceof ImmutableFooDto
&& equalTo((ImmutableFooDto) another);
}
private boolean equalTo(ImmutableFooDto another) {
return fee.equals(another.fee)
&& fii.equals(another.fii)
&& url.equals(another.url)
&& Arrays.equals(values, another.values);
}
/**
* Computes a hash code from attributes: {#code fee}, {#code fii}, {#code url}, {#code values}, {#code roles}.
* #return hashCode value
*/
#Override
public int hashCode() {
int h = 31;
h = h * 17 + fee.hashCode();
h = h * 17 + fii.hashCode();
h = h * 17 + url.hashCode();
h = h * 17 + Arrays.hashCode(values);
return h;
}
/**
* Prints the immutable value {#code FooDto} with attribute values.
* #return A string representation of the value
*/
#Override
public String toString() {
return "FooDto{"
+ "fee=" + fee
+ ", fii=" + fii
+ ", url=" + url
+ ", values=" + Arrays.toString(values)
+ "}";
}
/**
* Utility type used to correctly read immutable object from JSON representation.
* #deprecated Do not use this type directly, it exists only for the <em>Jackson</em>-binding infrastructure
*/
#Deprecated
#JsonDeserialize
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE)
static final class Json implements FooDto {
String fee;
String fii;
String url;
String[] values;
List<String> roles = Collections.emptyList();
boolean rolesIsSet;
#JsonProperty("fee")
public void setFee(String fee) {
this.fee = fee;
}
#JsonProperty("fii")
public void setFii(String fii) {
this.fii = fii;
}
#JsonProperty("url")
public void setUrl(String url) {
this.url = url;
}
#JsonProperty("values")
public void setValues(String[] values) {
this.values = values;
}
#Override
public String getFee() { throw new UnsupportedOperationException(); }
#Override
public String getFii() { throw new UnsupportedOperationException(); }
#Override
public String getUrl() { throw new UnsupportedOperationException(); }
#Override
public String[] getValues() { throw new UnsupportedOperationException(); }
}
/**
* #param json A JSON-bindable data structure
* #return An immutable value type
* #deprecated Do not use this method directly, it exists only for the <em>Jackson</em>-binding infrastructure
*/
#Deprecated
#JsonCreator
static ImmutableFooDto fromJson(Json json) {
ImmutableFooDto.Builder builder = ImmutableFooDto.builder();
if (json.fee != null) {
builder.fee(json.fee);
}
if (json.fii != null) {
builder.fii(json.fii);
}
if (json.url != null) {
builder.url(json.url);
}
if (json.values != null) {
builder.values(json.values);
}
return builder.build();
}
/**
* Creates an immutable copy of a {#link FooDto} value.
* Uses accessors to get values to initialize the new immutable instance.
* If an instance is already immutable, it is returned as is.
* #param instance The instance to copy
* #return A copied immutable FooDto instance
*/
public static ImmutableFooDto copyOf(FooDto instance) {
if (instance instanceof ImmutableFooDto) {
return (ImmutableFooDto) instance;
}
return ImmutableFooDto.builder()
.from(instance)
.build();
}
/**
* Creates a builder for {#link ImmutableFooDto ImmutableFooDto}.
* #return A new ImmutableFooDto builder
*/
public static ImmutableFooDto.Builder builder() {
return new ImmutableFooDto.Builder();
}
/**
* Builds instances of type {#link ImmutableFooDto ImmutableFooDto}.
* Initialize attributes and then invoke the {#link #build()} method to create an
* immutable instance.
* <p><em>{#code Builder} is not thread-safe and generally should not be stored in a field or collection,
* but instead used immediately to create instances.</em>
*/
public static final class Builder {
private static final long INIT_BIT_TITLE = 0x1L;
private static final long INIT_BIT_TECHNICAL_KEY = 0x2L;
private static final long INIT_BIT_URL = 0x4L;
private long initBits = 0x7L;
private long optBits;
private String fee;
private String fii;
private String url;
private String[] values;
private Builder() {
}
/**
* Fill a builder with attribute values from the provided {#code FooDto} instance.
* Regular attribute values will be replaced with those from the given instance.
* Absent optional values will not replace present values.
* Collection elements and entries will be added, not replaced.
* #param instance The instance from which to copy values
* #return {#code this} builder for use in a chained invocation
*/
public final Builder from(FooDto instance) {
Objects.requireNonNull(instance, "instance");
fee(instance.getFee());
fii(instance.getFii());
url(instance.getUrl());
values(instance.getValues());
return this;
}
/**
* Initializes the value for the {#link FooDto#getFee() fee} attribute.
* #param fee The value for fee
* #return {#code this} builder for use in a chained invocation
*/
public final Builder fee(String fee) {
this.fee = Objects.requireNonNull(fee, "fee");
initBits &= ~INIT_BIT_TITLE;
return this;
}
/**
* Initializes the value for the {#link FooDto#getFii() fii} attribute.
* #param fii The value for fii
* #return {#code this} builder for use in a chained invocation
*/
public final Builder fii(String fii) {
this.fii = Objects.requireNonNull(fii, "fii");
initBits &= ~INIT_BIT_TECHNICAL_KEY;
return this;
}
/**
* Initializes the value for the {#link FooDto#getUrl() url} attribute.
* #param url The value for url
* #return {#code this} builder for use in a chained invocation
*/
public final Builder url(String url) {
this.url = Objects.requireNonNull(url, "url");
initBits &= ~INIT_BIT_URL;
return this;
}
/**
* Initializes the value for the {#link FooDto#getValues() values} attribute.
* <p><em>If not set, this attribute will have a default value as defined by {#link FooDto#getValues() values}.</em>
* #param values The elements for values
* #return {#code this} builder for use in a chained invocation
*/
public final Builder values(String... values) {
this.values = values.clone();
return this;
}
/**
* Builds a new {#link ImmutableFooDto ImmutableFooDto}.
* #return An immutable instance of FooDto
* #throws java.lang.IllegalStateException if any required attributes are missing
*/
public ImmutableFooDto build() {
if (initBits != 0) {
throw new IllegalStateException(formatRequiredAttributesMessage());
}
return new ImmutableFooDto(this);
}
private String formatRequiredAttributesMessage() {
List<String> attributes = new ArrayList<String>();
if ((initBits & INIT_BIT_TITLE) != 0) attributes.add("fee");
if ((initBits & INIT_BIT_TECHNICAL_KEY) != 0) attributes.add("fii");
if ((initBits & INIT_BIT_URL) != 0) attributes.add("url");
return "Cannot build FooDto, some of required attributes are not set " + attributes;
}
}
private static <T> List<T> createSafeList(Iterable<? extends T> iterable, boolean checkNulls, boolean skipNulls) {
ArrayList<T> list;
if (iterable instanceof Collection<?>) {
int size = ((Collection<?>) iterable).size();
if (size == 0) return Collections.emptyList();
list = new ArrayList<T>();
} else {
list = new ArrayList<T>();
}
for (T element : iterable) {
if (skipNulls && element == null) continue;
if (checkNulls) Objects.requireNonNull(element, "element");
list.add(element);
}
return list;
}
private static <T> List<T> createUnmodifiableList(boolean clone, List<T> list) {
switch(list.size()) {
case 0: return Collections.emptyList();
case 1: return Collections.singletonList(list.get(0));
default:
if (clone) {
return Collections.unmodifiableList(new ArrayList<T>(list));
} else {
if (list instanceof ArrayList<?>) {
((ArrayList<?>) list).trimToSize();
}
return Collections.unmodifiableList(list);
}
}
}
}

I think the problem is that jackson can't find a way to construct your class.
Here's what works for me
import org.immutables.value.Value;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
#Value.Immutable
#Value.Style(privateNoargConstructor = true) //<<<< this is what you need I think
#JsonSerialize(as = ImmutableVal.class)
#JsonDeserialize(as = ImmutableVal.class)
interface Val {
int a();
#JsonProperty("b")
String second();
}
and
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class ValMain {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(
ImmutableVal.builder()
.a(1)
.second("B")
.build());
System.out.println(json);
//{"a":1,"b":"B"}
Val val = objectMapper.readValue(json, Val.class);
System.out.println(val);
//Val{a=1, second=B}
}
}
Then you can even get rid of the DTOs

Related

Flink Avro Error Expecting type to be a PojoTypeInfo

I'm trying to convert a HashMap<String, Object> to an Avro record. I get this runtime exception when I do a
DataStream<AvroRecord> dsRpvSchema = filteredVlfRPV.flatMap(new MessageFlattener()) .name("ToAvroSchema").uid("ToAvroSchema").startNewChain();
Not sure what the issue is with Flink converting the valid avro record to Flink Avro.
java.lang.IllegalStateException: Expecting type to be a PojoTypeInfo
at org.apache.flink.formats.avro.typeutils.AvroTypeInfo.generateFieldsFromAvroSchema(AvroTypeInfo.java:71)
at org.apache.flink.formats.avro.typeutils.AvroTypeInfo.<init>(AvroTypeInfo.java:55)
at org.apache.flink.formats.avro.utils.AvroKryoSerializerUtils.createAvroTypeInfo(AvroKryoSerializerUtils.java:81)
at org.apache.flink.api.java.typeutils.TypeExtractor.privateGetForClass(TypeExtractor.java:1653)
at org.apache.flink.api.java.typeutils.TypeExtractor.privateGetForClass(TypeExtractor.java:1559)
at org.apache.flink.api.java.typeutils.TypeExtractor.createTypeInfoWithTypeHierarchy(TypeExtractor.java:866)
at org.apache.flink.api.java.typeutils.TypeExtractor.privateCreateTypeInfo(TypeExtractor.java:747)
at org.apache.flink.api.java.typeutils.TypeExtractor.getUnaryOperatorReturnType(TypeExtractor.java:531)
at org.apache.flink.api.java.typeutils.TypeExtractor.getFlatMapReturnTypes(TypeExtractor.java:168)
at org.apache.flink.streaming.api.datastream.DataStream.flatMap(DataStream.java:637)
I do see two questions on this but no answers provided:
Flink Kafka : Expecting type to be a PojoTypeInfo
Deserialize Avro from kafka as SpecificRecord Failing. Expecting type to be a PojoTypeInfo
UPDATE: 02/01/2022. Below is the AvroRecord class definition.
import org.apache.avro.generic.GenericArray;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.util.Utf8;
import org.apache.avro.message.BinaryMessageEncoder;
import org.apache.avro.message.BinaryMessageDecoder;
import org.apache.avro.message.SchemaStore;
#org.apache.avro.specific.AvroGenerated
public class AvroRecord extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {
private static final long serialVersionUID = 9071485731787422200L;
public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"AvroRecord\",\"namespace\":\"com.sample.dataplatform.stream.avro\",\"fields\":[{\"name\":\"_id\",\"type\":\"string\",\"doc\":\"car_id\"}]}");
public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
private static SpecificData MODEL$ = new SpecificData();
private static final BinaryMessageEncoder<AvroRecord> ENCODER =
new BinaryMessageEncoder<AvroRecord>(MODEL$, SCHEMA$);
private static final BinaryMessageDecoder<AvroRecord> DECODER =
new BinaryMessageDecoder<AvroRecord>(MODEL$, SCHEMA$);
/**
* Return the BinaryMessageEncoder instance used by this class.
* #return the message encoder used by this class
*/
public static BinaryMessageEncoder<AvroRecord> getEncoder() {
return ENCODER;
}
/**
* Return the BinaryMessageDecoder instance used by this class.
* #return the message decoder used by this class
*/
public static BinaryMessageDecoder<AvroRecord> getDecoder() {
return DECODER;
}
/**
* Create a new BinaryMessageDecoder instance for this class that uses the specified {#link SchemaStore}.
* #param resolver a {#link SchemaStore} used to find schemas by fingerprint
* #return a BinaryMessageDecoder instance for this class backed by the given SchemaStore
*/
public static BinaryMessageDecoder<AvroRecord> createDecoder(SchemaStore resolver) {
return new BinaryMessageDecoder<AvroRecord>(MODEL$, SCHEMA$, resolver);
}
/**
* Serializes this AvroRecord to a ByteBuffer.
* #return a buffer holding the serialized data for this instance
* #throws java.io.IOException if this instance could not be serialized
*/
public java.nio.ByteBuffer toByteBuffer() throws java.io.IOException {
return ENCODER.encode(this);
}
/**
* Deserializes a AvroRecord from a ByteBuffer.
* #param b a byte buffer holding serialized data for an instance of this class
* #return a AvroRecord instance decoded from the given buffer
* #throws java.io.IOException if the given bytes could not be deserialized into an instance of this class
*/
public static AvroRecord fromByteBuffer(
java.nio.ByteBuffer b) throws java.io.IOException {
return DECODER.decode(b);
}
/** car_id */
private java.lang.CharSequence _id;
/**
* Default constructor. Note that this does not initialize fields
* to their default values from the schema. If that is desired then
* one should use <code>newBuilder()</code>.
*/
public AvroRecord() {}
/**
* All-args constructor.
* #param _id car_id
*/
public AvroRecord(java.lang.CharSequence _id) {
this._id = _id;
}
public org.apache.avro.specific.SpecificData getSpecificData() { return MODEL$; }
public org.apache.avro.Schema getSchema() { return SCHEMA$; }
// Used by DatumWriter. Applications should not call.
public java.lang.Object get(int field$) {
switch (field$) {
case 0: return _id;
default: throw new IndexOutOfBoundsException("Invalid index: " + field$);
}
}
// Used by DatumReader. Applications should not call.
#SuppressWarnings(value="unchecked")
public void put(int field$, java.lang.Object value$) {
switch (field$) {
case 0: _id = (java.lang.CharSequence)value$; break;
default: throw new IndexOutOfBoundsException("Invalid index: " + field$);
}
}
/**
* Gets the value of the '_id' field.
* #return car_id
*/
public java.lang.CharSequence getId$1() {
return _id;
}
/**
* Sets the value of the '_id' field.
* car_id
* #param value the value to set.
*/
public void setId$1(java.lang.CharSequence value) {
this._id = value;
}
/**
* Creates a new AvroRecord RecordBuilder.
* #return A new AvroRecord RecordBuilder
*/
public static com.sample.dataplatform.stream.avro.AvroRecord.Builder newBuilder() {
return new com.sample.dataplatform.stream.avro.AvroRecord.Builder();
}
/**
* Creates a new AvroRecord RecordBuilder by copying an existing Builder.
* #param other The existing builder to copy.
* #return A new AvroRecord RecordBuilder
*/
public static com.sample.dataplatform.stream.avro.AvroRecord.Builder newBuilder(com.sample.dataplatform.stream.avro.AvroRecord.Builder other) {
if (other == null) {
return new com.sample.dataplatform.stream.avro.AvroRecord.Builder();
} else {
return new com.sample.dataplatform.stream.avro.AvroRecord.Builder(other);
}
}
/**
* Creates a new AvroRecord RecordBuilder by copying an existing AvroRecord instance.
* #param other The existing instance to copy.
* #return A new AvroRecord RecordBuilder
*/
public static com.sample.dataplatform.stream.avro.AvroRecord.Builder newBuilder(com.sample.dataplatform.stream.avro.AvroRecord other) {
if (other == null) {
return new com.sample.dataplatform.stream.avro.AvroRecord.Builder();
} else {
return new com.sample.dataplatform.stream.avro.AvroRecord.Builder(other);
}
}
/**
* RecordBuilder for AvroRecord instances.
*/
#org.apache.avro.specific.AvroGenerated
public static class Builder extends org.apache.avro.specific.SpecificRecordBuilderBase<AvroRecord>
implements org.apache.avro.data.RecordBuilder<AvroRecord> {
/** car_id */
private java.lang.CharSequence _id;
/** Creates a new Builder */
private Builder() {
super(SCHEMA$);
}
/**
* Creates a Builder by copying an existing Builder.
* #param other The existing Builder to copy.
*/
private Builder(com.sample.dataplatform.stream.avro.AvroRecord.Builder other) {
super(other);
if (isValidValue(fields()[0], other._id)) {
this._id = data().deepCopy(fields()[0].schema(), other._id);
fieldSetFlags()[0] = other.fieldSetFlags()[0];
}
}
/**
* Creates a Builder by copying an existing AvroRecord instance
* #param other The existing instance to copy.
*/
private Builder(com.sample.dataplatform.stream.avro.AvroRecord other) {
super(SCHEMA$);
if (isValidValue(fields()[0], other._id)) {
this._id = data().deepCopy(fields()[0].schema(), other._id);
fieldSetFlags()[0] = true;
}
}
/**
* Gets the value of the '_id' field.
* car_id
* #return The value.
*/
public java.lang.CharSequence getId$1() {
return _id;
}
/**
* Sets the value of the '_id' field.
* car_id
* #param value The value of '_id'.
* #return This builder.
*/
public com.sample.dataplatform.stream.avro.AvroRecord.Builder setId$1(java.lang.CharSequence value) {
validate(fields()[0], value);
this._id = value;
fieldSetFlags()[0] = true;
return this;
}
/**
* Checks whether the '_id' field has been set.
* car_id
* #return True if the '_id' field has been set, false otherwise.
*/
public boolean hasId$1() {
return fieldSetFlags()[0];
}
/**
* Clears the value of the '_id' field.
* car_id
* #return This builder.
*/
public com.sample.dataplatform.stream.avro.AvroRecord.Builder clearId$1() {
_id = null;
fieldSetFlags()[0] = false;
return this;
}
#Override
#SuppressWarnings("unchecked")
public AvroRecord build() {
try {
AvroRecord record = new AvroRecord();
record._id = fieldSetFlags()[0] ? this._id : (java.lang.CharSequence) defaultValue(fields()[0]);
return record;
} catch (org.apache.avro.AvroMissingFieldException e) {
throw e;
} catch (java.lang.Exception e) {
throw new org.apache.avro.AvroRuntimeException(e);
}
}
}
#SuppressWarnings("unchecked")
private static final org.apache.avro.io.DatumWriter<AvroRecord>
WRITER$ = (org.apache.avro.io.DatumWriter<AvroRecord>)MODEL$.createDatumWriter(SCHEMA$);
#Override public void writeExternal(java.io.ObjectOutput out)
throws java.io.IOException {
WRITER$.write(this, SpecificData.getEncoder(out));
}
#SuppressWarnings("unchecked")
private static final org.apache.avro.io.DatumReader<AvroRecord>
READER$ = (org.apache.avro.io.DatumReader<AvroRecord>)MODEL$.createDatumReader(SCHEMA$);
#Override public void readExternal(java.io.ObjectInput in)
throws java.io.IOException {
READER$.read(this, SpecificData.getDecoder(in));
}
#Override protected boolean hasCustomCoders() { return true; }
#Override public void customEncode(org.apache.avro.io.Encoder out)
throws java.io.IOException
{
out.writeString(this._id);
}
#Override public void customDecode(org.apache.avro.io.ResolvingDecoder in)
throws java.io.IOException
{
org.apache.avro.Schema.Field[] fieldOrder = in.readFieldOrderIfDiff();
if (fieldOrder == null) {
this._id = in.readString(this._id instanceof Utf8 ? (Utf8)this._id : null);
} else {
for (int i = 0; i < 1; i++) {
switch (fieldOrder[i].pos()) {
case 0:
this._id = in.readString(this._id instanceof Utf8 ? (Utf8)this._id : null);
break;
default:
throw new java.io.IOException("Corrupt ResolvingDecoder.");
}
}
}
}
}
The AVRO schema (.avsc) file looks like this:
{
"namespace": "com.sample.dataplatform.stream.avro",
"type": "record",
"name": "AvroRecord",
"fields": [
{
"name": "_id",
"type": "string",
"doc": "car_id"
}
]
}
Any help is appreciated!

Avro generated class issue with json conversion [kotlin]

I'm having a strange issue with marshalling/unmarshalling an avro generated class. The error I'm getting is throwing a not an enum error - except there aren't any enum's in my class.
The error is specifically this:
com.fasterxml.jackson.databind.JsonMappingException: Not an enum: {"type":"record","name":"TimeUpdateTopic","namespace":"org.company.mmd.time","fields":[{"name":"time","type":"double"}]} (through reference chain: org.company.mmd.time.TimeUpdateTopic["schema"]->org.apache.avro.Schema$RecordSchema["enumDefault"])
Test Case
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import org.junit.Test
class TimeUpdateTopicTest {
val objectMapper = ObjectMapper().registerModule(JavaTimeModule())
#Test
fun decode() {
val t = TimeUpdateTopic(1.0)
objectMapper.writeValueAsString(t)
}
}
AVDL
#namespace("org.company.mmd.time")
protocol TimeMonitor {
record TimeUpdateTopic {
double time;
}
}
Java class generated by the avro task
/**
* Autogenerated by Avro
*
* DO NOT EDIT DIRECTLY
*/
package org.company.mmd.time;
import org.apache.avro.generic.GenericArray;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.util.Utf8;
import org.apache.avro.message.BinaryMessageEncoder;
import org.apache.avro.message.BinaryMessageDecoder;
import org.apache.avro.message.SchemaStore;
#org.apache.avro.specific.AvroGenerated
public class TimeUpdateTopic extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {
private static final long serialVersionUID = -4648318619505855037L;
public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"TimeUpdateTopic\",\"namespace\":\"org.company.mmd.time\",\"fields\":[{\"name\":\"time\",\"type\":\"double\"}]}");
public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
private static SpecificData MODEL$ = new SpecificData();
private static final BinaryMessageEncoder<TimeUpdateTopic> ENCODER =
new BinaryMessageEncoder<TimeUpdateTopic>(MODEL$, SCHEMA$);
private static final BinaryMessageDecoder<TimeUpdateTopic> DECODER =
new BinaryMessageDecoder<TimeUpdateTopic>(MODEL$, SCHEMA$);
/**
* Return the BinaryMessageEncoder instance used by this class.
* #return the message encoder used by this class
*/
public static BinaryMessageEncoder<TimeUpdateTopic> getEncoder() {
return ENCODER;
}
/**
* Return the BinaryMessageDecoder instance used by this class.
* #return the message decoder used by this class
*/
public static BinaryMessageDecoder<TimeUpdateTopic> getDecoder() {
return DECODER;
}
/**
* Create a new BinaryMessageDecoder instance for this class that uses the specified {#link SchemaStore}.
* #param resolver a {#link SchemaStore} used to find schemas by fingerprint
* #return a BinaryMessageDecoder instance for this class backed by the given SchemaStore
*/
public static BinaryMessageDecoder<TimeUpdateTopic> createDecoder(SchemaStore resolver) {
return new BinaryMessageDecoder<TimeUpdateTopic>(MODEL$, SCHEMA$, resolver);
}
/**
* Serializes this TimeUpdateTopic to a ByteBuffer.
* #return a buffer holding the serialized data for this instance
* #throws java.io.IOException if this instance could not be serialized
*/
public java.nio.ByteBuffer toByteBuffer() throws java.io.IOException {
return ENCODER.encode(this);
}
/**
* Deserializes a TimeUpdateTopic from a ByteBuffer.
* #param b a byte buffer holding serialized data for an instance of this class
* #return a TimeUpdateTopic instance decoded from the given buffer
* #throws java.io.IOException if the given bytes could not be deserialized into an instance of this class
*/
public static TimeUpdateTopic fromByteBuffer(
java.nio.ByteBuffer b) throws java.io.IOException {
return DECODER.decode(b);
}
#Deprecated public double time;
/**
* Default constructor. Note that this does not initialize fields
* to their default values from the schema. If that is desired then
* one should use <code>newBuilder()</code>.
*/
public TimeUpdateTopic() {}
/**
* All-args constructor.
* #param time The new value for time
*/
public TimeUpdateTopic(java.lang.Double time) {
this.time = time;
}
public org.apache.avro.specific.SpecificData getSpecificData() { return MODEL$; }
public org.apache.avro.Schema getSchema() { return SCHEMA$; }
// Used by DatumWriter. Applications should not call.
public java.lang.Object get(int field$) {
switch (field$) {
case 0: return time;
default: throw new org.apache.avro.AvroRuntimeException("Bad index");
}
}
// Used by DatumReader. Applications should not call.
#SuppressWarnings(value="unchecked")
public void put(int field$, java.lang.Object value$) {
switch (field$) {
case 0: time = (java.lang.Double)value$; break;
default: throw new org.apache.avro.AvroRuntimeException("Bad index");
}
}
/**
* Gets the value of the 'time' field.
* #return The value of the 'time' field.
*/
public double getTime() {
return time;
}
/**
* Sets the value of the 'time' field.
* #param value the value to set.
*/
public void setTime(double value) {
this.time = value;
}
/**
* Creates a new TimeUpdateTopic RecordBuilder.
* #return A new TimeUpdateTopic RecordBuilder
*/
public static org.company.mmd.time.TimeUpdateTopic.Builder newBuilder() {
return new org.company.mmd.time.TimeUpdateTopic.Builder();
}
/**
* Creates a new TimeUpdateTopic RecordBuilder by copying an existing Builder.
* #param other The existing builder to copy.
* #return A new TimeUpdateTopic RecordBuilder
*/
public static org.company.mmd.time.TimeUpdateTopic.Builder newBuilder(org.company.mmd.time.TimeUpdateTopic.Builder other) {
if (other == null) {
return new org.company.mmd.time.TimeUpdateTopic.Builder();
} else {
return new org.company.mmd.time.TimeUpdateTopic.Builder(other);
}
}
/**
* Creates a new TimeUpdateTopic RecordBuilder by copying an existing TimeUpdateTopic instance.
* #param other The existing instance to copy.
* #return A new TimeUpdateTopic RecordBuilder
*/
public static org.company.mmd.time.TimeUpdateTopic.Builder newBuilder(org.company.mmd.time.TimeUpdateTopic other) {
if (other == null) {
return new org.company.mmd.time.TimeUpdateTopic.Builder();
} else {
return new org.company.mmd.time.TimeUpdateTopic.Builder(other);
}
}
/**
* RecordBuilder for TimeUpdateTopic instances.
*/
public static class Builder extends org.apache.avro.specific.SpecificRecordBuilderBase<TimeUpdateTopic>
implements org.apache.avro.data.RecordBuilder<TimeUpdateTopic> {
private double time;
/** Creates a new Builder */
private Builder() {
super(SCHEMA$);
}
/**
* Creates a Builder by copying an existing Builder.
* #param other The existing Builder to copy.
*/
private Builder(org.company.mmd.time.TimeUpdateTopic.Builder other) {
super(other);
if (isValidValue(fields()[0], other.time)) {
this.time = data().deepCopy(fields()[0].schema(), other.time);
fieldSetFlags()[0] = other.fieldSetFlags()[0];
}
}
/**
* Creates a Builder by copying an existing TimeUpdateTopic instance
* #param other The existing instance to copy.
*/
private Builder(org.company.mmd.time.TimeUpdateTopic other) {
super(SCHEMA$);
if (isValidValue(fields()[0], other.time)) {
this.time = data().deepCopy(fields()[0].schema(), other.time);
fieldSetFlags()[0] = true;
}
}
/**
* Gets the value of the 'time' field.
* #return The value.
*/
public double getTime() {
return time;
}
/**
* Sets the value of the 'time' field.
* #param value The value of 'time'.
* #return This builder.
*/
public org.company.mmd.time.TimeUpdateTopic.Builder setTime(double value) {
validate(fields()[0], value);
this.time = value;
fieldSetFlags()[0] = true;
return this;
}
/**
* Checks whether the 'time' field has been set.
* #return True if the 'time' field has been set, false otherwise.
*/
public boolean hasTime() {
return fieldSetFlags()[0];
}
/**
* Clears the value of the 'time' field.
* #return This builder.
*/
public org.company.mmd.time.TimeUpdateTopic.Builder clearTime() {
fieldSetFlags()[0] = false;
return this;
}
#Override
#SuppressWarnings("unchecked")
public TimeUpdateTopic build() {
try {
TimeUpdateTopic record = new TimeUpdateTopic();
record.time = fieldSetFlags()[0] ? this.time : (java.lang.Double) defaultValue(fields()[0]);
return record;
} catch (org.apache.avro.AvroMissingFieldException e) {
throw e;
} catch (java.lang.Exception e) {
throw new org.apache.avro.AvroRuntimeException(e);
}
}
}
#SuppressWarnings("unchecked")
private static final org.apache.avro.io.DatumWriter<TimeUpdateTopic>
WRITER$ = (org.apache.avro.io.DatumWriter<TimeUpdateTopic>)MODEL$.createDatumWriter(SCHEMA$);
#Override public void writeExternal(java.io.ObjectOutput out)
throws java.io.IOException {
WRITER$.write(this, SpecificData.getEncoder(out));
}
#SuppressWarnings("unchecked")
private static final org.apache.avro.io.DatumReader<TimeUpdateTopic>
READER$ = (org.apache.avro.io.DatumReader<TimeUpdateTopic>)MODEL$.createDatumReader(SCHEMA$);
#Override public void readExternal(java.io.ObjectInput in)
throws java.io.IOException {
READER$.read(this, SpecificData.getDecoder(in));
}
#Override protected boolean hasCustomCoders() { return true; }
#Override public void customEncode(org.apache.avro.io.Encoder out)
throws java.io.IOException
{
out.writeDouble(this.time);
}
#Override public void customDecode(org.apache.avro.io.ResolvingDecoder in)
throws java.io.IOException
{
org.apache.avro.Schema.Field[] fieldOrder = in.readFieldOrderIfDiff();
if (fieldOrder == null) {
this.time = in.readDouble();
} else {
for (int i = 0; i < 1; i++) {
switch (fieldOrder[i].pos()) {
case 0:
this.time = in.readDouble();
break;
default:
throw new java.io.IOException("Corrupt ResolvingDecoder.");
}
}
}
}
}
Am I doing something stupid and/or wrong here? Or is this an actual bug
Updates
I'm able to get JSON out using this function:
inline fun <reified T: SpecificRecordBase> StringFromAvroGenerated(obj: T) : String {
val schema = obj.schema
val writer = SpecificDatumWriter(T::class.java)
val stream = ByteArrayOutputStream()
var jsonEncoder = EncoderFactory.get().jsonEncoder(schema, stream)
writer.write(obj, jsonEncoder)
jsonEncoder.flush()
return stream.toString("UTF-8")
}
but I was assuming this should be automatic with Jackson
So it appears there are two ways to solve my issues (thanks to JsonMappingException when serializing avro generated object to json)
Write a Jackson MixIn to handle the getSchema call
So the first option required me to create a Mixin such as this:
abstract class AvroMixIn {
#JsonIgnore
abstract fun getSchema(): org.apache.avro.Schema
#JsonIgnore
abstract fun getSpecificData() : org.apache.avro.specific.SpecificData
}
And then when i make an object mapper:
val objectMapper = ObjectMapper()
.registerModule(JavaTimeModule())
.addMixIn(Object::class.java, AvroMixIn::class.java)
I chose Object::class.java instead of the actual class because it should apply to all classes. Probably a better solution is to apply it to a shared base-class all the AvroGenerated stuff has.
Rewrite the Avro Velocity Templates to automatically add this
This is actually the 1st approach I took because it seemed more "seemless".
1) Check out the avro project
2) Copy enum.vm, fixed.vm, protocol.vm, record.vm into a /avro_templates directory off the main root of my project
3) Add the #com.fasterxml.jackson.annotation.JsonIgnore property to the template:
#end
#com.fasterxml.jackson.annotation.JsonIgnore
public org.apache.avro.specific.SpecificData getSpecificData() { return MODEL$; }
#com.fasterxml.jackson.annotation.JsonIgnore
public org.apache.avro.Schema getSchema() { return SCHEMA$; }
// Used by DatumWriter. Applications should not call.
4) Update the gradle task:
avro {
dateTimeLogicalType="JSR310"
templateDirectory = "avro_templates/"
}
5) re-build avro classes
(everything now works)

Jackson:UnrecognisedPropertyException

I have the following classes:
LocationCustomDataItem.java
public class LocationCustomDataItem {
private String attributeNumber;
private String attributeLabel;
private String attributeValue;
public LocationCustomDataItem() {
}
public LocationCustomDataItem(final String attributeNumber, final String attributeLabel, final String attributeValue) {
this.attributeNumber = attributeNumber;
this.attributeLabel = attributeLabel;
this.attributeValue = attributeValue;
}
/**
* #return the attributeNumber
*/
public String getAttributeNumber() {
return attributeNumber;
}
/**
* #param attributeNumber the attributeNumber to set
*/
public void setAttributeNumber(String attributeNumber) {
this.attributeNumber = attributeNumber;
}
/**
* #return the attributeLabel
*/
public String getAttributeLabel() {
return attributeLabel;
}
/**
* #param attributeLabel the attributeLabel to set
*/
public void setAttributeLabel(String attributeLabel) {
this.attributeLabel = attributeLabel;
}
/**
* #return the attributeValue
*/
public String getAttributeValue() {
return attributeValue;
}
/**
* #param attributeValue the attributeValue to set
*/
public void setAttributeValue(String attributeValue) {
this.attributeValue = attributeValue;
}
#Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, false);
}
#Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE, false);
}
LocationCustomDataAttributes.java
public class LocationCustomDataAttributes {
private final List<LocationCustomDataItem> locationCustomDataItems;
public LocationCustomDataAttributes() {
this.locationCustomDataItems = new ArrayList<>();
}
public LocationCustomDataAttributes(final List<LocationCustomDataItem> locationCustomDataItems) {
this.locationCustomDataItems = locationCustomDataItems;
}
/**
* #return unmodifiable locationCustomDataItems list
*/
public List<LocationCustomDataItem> getLocationCustomDataItems() {
return Collections.unmodifiableList(this.locationCustomDataItems);
}
/**
* Adds LocationCustoDataItem to internal collection
*
* #param item LocationCustomDataItem to add to item list
*/
public void addItem(final LocationCustomDataItem item) {
this.locationCustomDataItems.add(item);
}
#Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, false);
}
#Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE, false);
}
and this test json:
{
"locationCustomDataAttributes" : {
"locationCustomDataItems" : [ {
"attributeLabel" : "testLabel1",
"attributeNumber" : "testNumber1",
"attributeValue" : "testLabel1"
}, {
"attributeLabel" : "testLabel2",
"attributeNumber" : "testNumber2",
"attributeValue" : "testLabel2"
} ]
}
}
I'm trying to use an ObjectMapper to convert the json to the object, but it is throwing an unrecognisedPropertyException around "locationCustomDataAttributes":
MapperTest.java
#Test
public void test() throws JsonParseException, JsonMappingException, IOException {
ObjectMapper om =new ObjectMapper();
LocationCustomDataAttributes actual = om.readValue(json, LocationCustomDataAttributes.class);
LocationCustomDataAttributes expected = new LocationCustomDataAttributes();
expected.addItem(new LocationCustomDataItem("testNumber1", "testLabel1", "testValue1"));
expected.addItem(new LocationCustomDataItem("testNumber2", "testLabel2", "testValue2"));
assertThat(actual).isEqualTo(expected);
}
error message:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "locationCustomDataAttributes" (class com.lmig.ci.fnol.transformer.domain.LocationCustomDataAttributes), not marked as ignorable (one known property: "locationCustomDataItems"])
at [Source: {"locationCustomDataAttributes" : {"locationCustomDataItems" : [ {"attributeLabel" : "testLabel1","attributeNumber" : "testNumber1","attributeValue" : "testLabel1"},{"attributeLabel" : "testLabel2","attributeNumber" : "testNumber2","attributeValue" : "testLabel2"}]}}; line: 1, column: 36] (through reference chain: com.lmig.ci.fnol.transformer.domain.LocationCustomDataAttributes["locationCustomDataAttributes"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:833)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1096)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1467)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1445)
//etc...`
I don't ave a massive amount of experience working with Jackson directly so I haven't annotated the class itself yet, but from previous efforts(e.g. with Spring controllers) the conversion happens automatically without the need for annotations on the class. In this instance that doesn't look like the case, what am I missing from the class, or does the current class structure not lend itself to automatic conversion by Jackson for some reason?
om.readValue(json, LocationCustomDataAttributes.class)
This line asks to parse a LocationCustomDataAttributes object from the JSON document. But JSON actually contains a wrapper object with a property that can be parsed into a LocationCustomDataAttributes object. Solutions:
Create a reader for a wrapped object. E.g.
ObjectReader reader = om
.readerFor(LocationCustomDataAttributes.class)
.withRootName("locationCustomDataAttributes");
LocationCustomDataAttributes actual = reader.readValue(json);
Define a wrapper class
class AttributesWrapper {
private LocationCustomDataAttributes locationCustomDataAttributes;
// add getters, setters, constructors etc
}
and then parse it:
LocationCustomDataAttributes actual = om
.readValue(json, AttributesWrapper.class)
.getLocationCustomDataAttributes();

Cannot set value on more than one object [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
I have an object I created called annuals... i have getters and setters for this object and it implements comparable. When I create multiples of this object to add to a list, I end up with one object with values but all subsequent objects are have null values. How do I prevent this? Code is blow broken down by object and creating object.
Thanks in advance...
Object:
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Date;
/**
* #author
*
*/
public class Annuals implements Comparable<Annuals>
{
private BigDecimal value;
private Date dateCalculated;
private BigDecimal dataYear;
private String type;
/**
* #return the value
*/
public BigDecimal getValue()
{
return value;
}
/**
* #param value the value to set
*/
public void setValue(BigDecimal value)
{
this.value = value;
}
/**
* #return the dateCalculated
*/
public Date getDateCalculated()
{
return dateCalculated;
}
/**
* #param dateCalculated the dateCalculated to set
*/
public void setDateCalculated(Date dateCalculated)
{
this.dateCalculated = dateCalculated;
}
/**
* #return the dataYear
*/
public BigDecimal getDataYear()
{
return dataYear;
}
/**
* #param dataYear the dataYear to set
*/
public void setDataYear(BigDecimal dataYear)
{
this.dataYear = dataYear;
}
/**
* #return the type
*/
public String getType()
{
return type;
}
/**
* #param type the type to set
*/
public void setType(String type)
{
this.type = type;
}
/* (non-Javadoc)
* #see java.lang.Object#toString()
*/
#Override
public String toString()
{
return "Annuals [value=" + value + ", dateCalculated=" + dateCalculated + ", dataYear=" + dataYear + ", type="
+ type + "]";
}
public static Comparator<Annuals> yearComparator = new Comparator<Annuals>()
{
#Override
public int compare(Annuals o1, Annuals o2)
{
return o1.getDataYear().compareTo(o2.getDataYear());
}
};
#Override
public int compareTo(Annuals o)
{
return this.value.compareTo(o.value);
}
}
Creating Object:
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
public class CreateCompanies
{
private List<CompanyInfoDO> companiesList = new ArrayList<CompanyInfoDO>();
/**
* #return the companiesList
*/
public List<CompanyInfoDO> getCompaniesList()
{
return companiesList;
}
/**
* #param companiesList the companiesList to set
*/
public void setCompaniesList(List<CompanyInfoDO> companiesList)
{
this.companiesList = companiesList;
}
public CreateCompanies()
{
CompanyInfoDO company = new CompanyInfoDO();
company.setCompanyName("Ford");
company.setDate(Calendar.getInstance().getTime().toString());
company.setShares("39000000000");
company.setTicker("f");
company.setStockPrice(BigDecimal.valueOf(11.14));
company.setTotalOutstandingSharesAnnuals(getTotalSharesOutstandingList());
company.setNetIncomeAnnuals(getNetIncomeList());
companiesList.add(company);
}
private List<Annuals> getTotalSharesOutstandingList()
{
List<Annuals> annualsList = new ArrayList<Annuals>();
Annuals annual = new Annuals();
annual.setDataYear(BigDecimal.valueOf(2013));
annual.setValue(BigDecimal.valueOf(3984.0));
annual.setType(InvestConstants.TOTAL_SHARES_OUTSTANDING);
Annuals annual1 = new Annuals();
annual.setDataYear(BigDecimal.valueOf(2014));
annual.setValue(BigDecimal.valueOf(4009.0));
annual.setType(InvestConstants.TOTAL_SHARES_OUTSTANDING);
Annuals annual2 = new Annuals();
annual.setDataYear(BigDecimal.valueOf(2015));
annual.setValue(BigDecimal.valueOf(4031.0));
annual.setType(InvestConstants.TOTAL_SHARES_OUTSTANDING);
Annuals annual3 = new Annuals();
annual.setDataYear(BigDecimal.valueOf(2016));
annual.setValue(BigDecimal.valueOf(3931.0));
annual.setType(InvestConstants.TOTAL_SHARES_OUTSTANDING);
annualsList.add(annual);
annualsList.add(annual1);
annualsList.add(annual2);
annualsList.add(annual3);
return annualsList;
}
private List<Annuals> getNetIncomeList()
{
List<Annuals> annualsList = new ArrayList<Annuals>();
Annuals annual = new Annuals();
annual.setDateCalculated(Calendar.getInstance().getTime());
annual.setType(InvestConstants.NET_INCOME);
annual.setValue(BigDecimal.valueOf(11953.0));
annual.setDataYear(BigDecimal.valueOf(2013));
System.out.println("Annual: "+ annual.toString());
annualsList.add(annual);
Annuals annual2 = new Annuals();
annual.setDateCalculated(Calendar.getInstance().getTime());
annual.setType(InvestConstants.NET_INCOME);
annual.setValue(new BigDecimal(1231.0));
BigDecimal val2 = new BigDecimal(2014);
annual.setDataYear(val2);
System.out.println("Annual 2 : "+ annual2.toString());
Annuals annual3 = new Annuals();
annual.setDateCalculated(Calendar.getInstance().getTime());
annual.setType(InvestConstants.NET_INCOME);
annual.setValue(BigDecimal.valueOf(7373.0));
annual.setDataYear(BigDecimal.valueOf(2015));
Annuals annual4 = new Annuals();
annual.setDateCalculated(Calendar.getInstance().getTime());
annual.setType(InvestConstants.NET_INCOME);
annual.setValue(BigDecimal.valueOf(4596.0));
annual.setDataYear(BigDecimal.valueOf(2016));
//annualsList.add(annual);
annualsList.add(annual2);
annualsList.add(annual3);
annualsList.add(annual4);
System.out.println("Net Annuals List: Creating Company: "+annualsList.toString());
return annualsList;
}
Annuals annual1 = new Annuals();
annual.setDataYear(BigDecimal.valueOf(2014));
annual.setValue(BigDecimal.valueOf(4009.0));
annual.setType(InvestConstants.TOTAL_SHARES_OUTSTANDING);
You are creating new instances named annual1, annual2 and so on - but only ever modify annual.
You're reusing always the same variable annual.
Pay attention to your code, after creating a new instance of Annual and assigning the instance to a variable annual1 or annual2 you're reusing the old variable annual.
Annuals annual1 = new Annuals();
annual.setDataYear(BigDecimal.valueOf(2014));

Cannot sort an array list using Collections.sort after implementing Comparable

As the title suggests, I am trying to Sort my ArrayList of objects, and those objects have implemented comparable and have overriden CompareTo
However when I got to sort my arraylist i get this error
I can't seem to understand why I am getting this problem? Can anybody help?
ItemList Class:
package stories.cs2800;
import java.util.ArrayList;
import java.util.Collections;
import javax.swing.AbstractListModel;
#SuppressWarnings("serial")
public class ItemList extends AbstractListModel<Item> {
private ArrayList<Item> items;
/**
* Constructor that initializes the array list.
*/
public ItemList() {
items = new ArrayList<Item>();
}
#Override
public int getSize() {
return items.size();
}
/**
* Method to get item based on the index.
* #param argIndex - Takes parameter of type int.
* #return Returns item at the index.
*/
#Override
public Item getElementAt(int argIndex) throws IndexOutOfBoundsException {
if (argIndex < 0 || argIndex >= items.size()) {
throw new IndexOutOfBoundsException();
}
return items.get(argIndex);
}
/**
* Method that gets and Item element based on the name.
*
* #param argName - takes parameter of type String.
* #return Returns the entire item object if name matches, else null.
*/
public Item getElementByName(String argName) {
for (Item i : items) {
if (i.getName().equals(argName)) {
return i;
}
}
return null;
}
/**
* Method to add another Item into the array list.
* #param Takes parameter of type item.
* #see ArrayList#add
*/
public void add(Item next) {
items.add(next);
Collections.sort(items);
}
/**
* Boolean method to check if list contains the item of type Item.
*
* #param Takes parameter of type item.
* #return returns boolean value of true or false if item is contained.
*/
public Boolean contains(Item argItem) {
return items.contains(argItem);
}
/**
* Boolean method remove to remove item of type Item from list.
*
* #param Takes parameter of type Item.
* #return returns boolean value of true or false if item is removed.
*/
public Boolean remove(Item argItem) {
return items.remove(argItem);
}
/**
* Boolean method that removes and item based on its index.
*
* #argIndex Takes a parameter of type int.
* #return returns boolean value of true or false if item was removed based on index.
*/
public Boolean remove(int argIndex) throws IndexOutOfBoundsException {
if (argIndex < 0 || argIndex >= items.size()) {
throw new IndexOutOfBoundsException();
}
return items.remove(items.get(argIndex));
}
/**
* Method to find the index of an item object.
*
* #param Takes parameter of type Item.
* #return Returns item index based on the item object entered.
*/
public int indexOf(Item argItem) {
return items.indexOf(argItem);
}
/**
* Method to check if item changed.
*
* #param Takes parameter of type Item.
*/
public void changed(Item argItem) {
fireContentsChanged(this, items.indexOf(items), items.indexOf(items));
/*Method called when one or more items have changed */
}
}
SingleItem Class:
package stories.cs2800
public class SingleItem implements Comparable<Item>, Item {
private String name;
private float value;
private Item child;
/**
* Constructor for the SingleItem object.
*
* #param argName Stores the name that is set in constructor
* #param argValue Stores the float value that is set in Constructor
* #param argChild Stores the value of the child element
*/
public SingleItem(String argName, float argValue, Item argChild) {
name = argName;
value = argValue;
child = argChild;
}
/**
* Getter method to get the value of the name variable.
*
* #return returns the name
*/
#Override
public String getName() {
return this.name;
}
/**
* Getter method to get the value of the Float variable.
*
* #return value set in the value variable
*
*/
#Override
public Float getValue() {
return this.value;
}
/**
* Setter method to set the value of the Float - No return type.
* #param argFloat - Takes parameter of type Float using Wrapper class.
*/
#Override
public void setValue(Float argFloat) {
this.value = argFloat;
}
/**
* Method to get the description.
*
* #return Returns the a string with the description
*/
#Override
public String getDescription() {
return "Single items have no description";
}
/**
* Getter method for child element.
*
* #return returns the value of child element
*/
public Item getChild() {
return this.child;
}
/**
* Method for adding items.
* #param child - Takes parameter of type Item.
* #return Returns Exception when child is null.
*
*/
#Override
public void add(Item child) {
if (this.child != null) {
throw new IllegalStateException();
}
this.child = child;
}
/**
* Method for ItemVisitor.
* #param argVisitor - Takes parameter of ItemVisitor to add current class.
* #return Currently no valid method!.
*
*/
#Override
public <T> void accept(ItemVisitor<T> argVisitor) {
argVisitor.add(this);
}
/**
* Method that takes Boolean as a parameter.
* #param argBool - Takes parameter of type boolean.
* #return Returns exception.
*/
#Override
public void open(boolean argBool) throws IllegalStateException {
throw new IllegalStateException();
}
/**
* Method that compares name to name entered as a parameter.
* #param item - Takes parameter of type item.
* #return Returns an int based on comparison of name. E.g. 0 = same, 1 = different.
*/
#Override
public int compareTo(Item item) {
return this.name.compareTo(item.getName());
}
/**
* Method to check if Open.
*
* #return Always returns true.
*/
#Override
public boolean isOpen() {
return true;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
SingleItem other = (SingleItem) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
/**
* toString method to get values of elements.
*
* #return Returns a sentence with the values of all elements.
*/
#Override
public String toString() {
return "Name: " + getName() + ", Value: " + getValue()
+ ", Description: "
+ getDescription();
}
}
In short, Item doesn't implement Comparable. And the list is a list of Item.
Details here. In the code above, items = new ArrayList<Item>();. Which means compiler only knows that in list items, the type is Item. So when invoke Collections.sort(items), java compiler found Item doesn't implement Comparable. And there will be an error as shown at the beginning.
How to fix? Change definition of Item, make it implement Comparable.
So as you can see, there is nothing about SingleItem. Because it is the impl and items sees only interface Item.

Categories