I have this Enum defined:
public enum OutputFormatEnum {
PDF("pdf"),
DOCX("docx"),
XLSX("xlsx"),
PPTX("pptx"),
HTML("html"),
PRN("prn"),
CSV("csv"),
RTF("rtf"),
JPG("jpg"),
PNG("png"),
SVG("svg"),
EPS("eps"),
BMP("bmp"),
GIF("gif"),
TXT("txt");
private String value;
OutputFormatEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
#Override
public String toString() {
return String.valueOf(value);
}
public static OutputFormatEnum fromValue(String value) {
for (OutputFormatEnum b : OutputFormatEnum.values())
if (b.value.equals(value))
return b;
throw new IllegalArgumentException("Unexpected value '" + value + "'");
}
}
I have a model object that has a OutputFormatEnum variable called OutputFormat. When I set this variable to OutputFormatEnum.PDF, it is initially registered as "pdf" which is what it should be. When I then execute the following code:
ByteArrayOutputStream streamTemplate = new ByteArrayOutputStream();
xmlMapper.writeValue(streamTemplate, {model_object_with_enum_variable});
It sets the value of OutputFormat in streamTemplate to "PDF", where it should be "pdf" (the value of OutputFormatEnum.PDF). Any idea as to why this is happening?
You need to add #JsonValue to the getValue() method so that this method is used by Jackson to serialize the instance:
public enum OutputFormatEnum {
PDF("pdf"),
DOCX("docx"),
XLSX("xlsx"),
PPTX("pptx"),
HTML("html"),
PRN("prn"),
CSV("csv"),
RTF("rtf"),
JPG("jpg"),
PNG("png"),
SVG("svg"),
EPS("eps"),
BMP("bmp"),
GIF("gif"),
TXT("txt");
private String value;
OutputFormatEnum(String value) {
this.value = value;
}
#JsonValue
public String getValue() {
return value;
}
#Override
public String toString() {
return String.valueOf(value);
}
public static OutputFormatEnum fromValue(String value) {
for (OutputFormatEnum b : OutputFormatEnum.values())
if (b.value.equals(value))
return b;
throw new IllegalArgumentException("Unexpected value '" + value + "'");
}
}
Given that you are serializing this to XML, you might need to use #XmlValue instead:
public enum OutputFormatEnum {
PDF("pdf"),
DOCX("docx"),
XLSX("xlsx"),
PPTX("pptx"),
HTML("html"),
PRN("prn"),
CSV("csv"),
RTF("rtf"),
JPG("jpg"),
PNG("png"),
SVG("svg"),
EPS("eps"),
BMP("bmp"),
GIF("gif"),
TXT("txt");
private String value;
OutputFormatEnum(String value) {
this.value = value;
}
#XmlValue
public String getValue() {
return value;
}
#Override
public String toString() {
return String.valueOf(value);
}
public static OutputFormatEnum fromValue(String value) {
for (OutputFormatEnum b : OutputFormatEnum.values())
if (b.value.equals(value))
return b;
throw new IllegalArgumentException("Unexpected value '" + value + "'");
}
}
In addition to this, you need to enable the support for the standard JAXB annotations as follows:
xmlMapper.registerModule(new JaxbAnnotationModule());
Related
I am trying to deserialize a JSON response with custom enum values, but instead of mapping with the custom value, the enum is being set with its ordinal value. I have searched a lot and I can not figure out what I am doing wrong. Any help would be great.
The response is
{"id":12, "status":1}
Corresponding enum object and enum is
public class Car {
int id;
CarStatus status;
}
public enum CarStatus {
READY(1),
WAITING(2);
private int value;
CarStatus(int value) {
this.value = value;
}
#JsonValue
public int getValue() {
return value;
}
}
The status is set to WAITING, but I expect it to be set to READY.
your enum miss #JsonCreator
try like this:
public enum CarStatus {
READY(1),
WAITING(2);
private int value;
CarStatus(int value) {
this.value = value;
}
#JsonValue
public int getValue() {
return value;
}
#JsonCreator
public static CarStatus getItem(int code){
for(CarStatus item : values()){
if(item.getValue() == code){
return item;
}
}
return null;
}
}
you can see my code in github: https://github.com/onemaomao/java-common-mistakes/tree/master/src/main/java/org/geekbang/time/questions/stackoverflow/reslove/q1
This seems so be a known problem for enums when using an integer in combination with only a #JsonValue annotation. There are open issues on Github which refer to this (e.g. 1 and 2) which are currently planned for version 2.13.
In the meantime, you can solve this by adding a #JsonCreator which returns the corresponding CarStatus:
public enum CarStatus {
READY(1),
WAITING(2);
private final int value;
CarStatus(int value) {
this.value = value;
}
#JsonValue
public int getValue() {
return this.value;
}
#JsonCreator
public static CarStatus getByValue(int value) {
for (CarStatus status : values()) {
if (status.value == value) {
return status;
}
}
return null;
}
}
Code to test:
ObjectMapper objectMapper = new ObjectMapper();
Car original = new Car();
original.setId(45);
original.setStatus(CarStatus.READY);
String json = objectMapper.writeValueAsString(original);
Car reconstruction = objectMapper.readValue(json, Car.class);
System.out.println(json);
System.out.println(reconstruction.getStatus());
Output:
{"id":45,"status":1}
READY
I recheck some documentation on tree structures and some relating answers on the subject here on stackoverflow.com, for example this one and they mostly use raw types or just one specific type which does not work for my problem. I have a file which stores meta as an XML, so parsing wasn't a problem but I still need a clean data structure to store the actual information.
The actual part of the file
<File>
<Meta>
<Generator>default</Generator>
<HeaderHash>110EbosCOut9ooqtIza4yHdT9xx+wUAp1VMfPqpQKwM=</HeaderHash>
<Color/>
<MemoryProtection>
<ProtectTitle>False</ProtectTitle>
<ProtectUserName>False</ProtectUserName>
<ProtectPassword>True</ProtectPassword>
<ProtectURL>False</ProtectURL>
<ProtectNotes>False</ProtectNotes>
</MemoryProtection>
<CustomIcons/>
<Binaries />
<CustomData/>
</Meta>
</<File>
The data structure I came up with
public class MetadataEntry {
public MetadataEntry() {
this.entity = new Entry();
}
private class Entry<T> {
private String name;
private T value;
private boolean isGroup;
private void setValue(T value) {
if (value instanceof String) {
this.value = value;
this.isGroup = false;
}
if (value instanceof MetadataEntry) {
if (isGroup()) {
((List<MetadataEntry>) this.value).add((MetadataEntry) value);
} else {
this.value = (T) new ArrayList<MetadataEntry>();
this.isGroup = true;
setValue(value);
}
}
}
}
private Entry entity;
public void setName(String name) {
this.entity.name = name;
}
public String getName() {
return this.entity.name;
}
public void setValue(String value) {
entity.setValue(value);
}
public void setValue(MetadataEntry value) {
entity.setValue(value);
}
public boolean isGroup() {
return this.entity.isGroup;
}
public List<MetadataEntity> getChildNodes() {
if (isGroup()) {
return (List<MetadataEntry>) this.entity.value;
}
return null;
}
public String getValue() {
if (!isGroup()) {
return (String) this.entity.value;
}
return null;
}
}
So, could you suggest how to make it cleaner, without using raw types if it is clearly not necessary and avoid using instanceof? Or even better point me out please where to read more about it.
Argumentative comments would be much more appreciated instead of down-voting if for some reason the topic is not of interest.
Composite Pattern will be suitable for your case, citing 《Design Patterns》GoF
Compose objects into tree structures to represent part-whole hierarchies.
Composite lets clients treat individual objects and compositions of objects
uniformly.
The following code composites your tree structure with Composite Pattern applied.
/**
* declares the interface for objects in the composition
* #param <T>
*/
interface MetaEntry<T> extends Iterable<MetaEntry<T>> {
T getName();
MetaEntry<T> setName(T name);
T getValue();
MetaEntry<T> setValue(T name);
MetaEntry<T> add(MetaEntry<T> entry);
MetaEntry<T> remove(MetaEntry<T> entry);
}
/**
* represents leaf objects in the composition. A leaf has no children.
* #param <T>
*/
class SimpleMetaEntry<T> implements MetaEntry<T> {
T name;
T value;
#Override
public T getName() {
return name;
}
#Override
public MetaEntry<T> setName(T name) {
this.name = name;
return this;
}
#Override
public T getValue() {
return value;
}
#Override
public MetaEntry<T> setValue(T value) {
this.value = value;
return this;
}
#Override
public MetaEntry<T> add(MetaEntry<T> entry) {
throw new UnsupportedOperationException();
}
#Override
public MetaEntry<T> remove(MetaEntry<T> entry) {
throw new UnsupportedOperationException();
}
#Override
public Iterator<MetaEntry<T>> iterator() {
// we want to treat all objects uniformly.
return new Iterator<MetaEntry<T>>() {
#Override
public boolean hasNext() {
return false;
}
#Override
public MetaEntry<T> next() {
return null;
}
};
}
#Override
public String toString() {
return "<" + name + (value == null ? "/>" : ">" + value + "</" + name + ">\n");
}
}
/**
* defines behavior for components having children.
* #param <T>
*/
class CompositeMetaEntry<T> implements MetaEntry<T> {
T name;
T value;
List<MetaEntry<T>> list = new ArrayList<MetaEntry<T>>();
#Override
public T getName() {
return name;
}
#Override
public MetaEntry<T> setName(T name) {
this.name = name;
return this;
}
#Override
public T getValue() {
return value;
}
#Override
public MetaEntry<T> setValue(T value) {
this.value = value;
return this;
}
#Override
public MetaEntry<T> add(MetaEntry<T> entry) {
list.add(entry);
return this;
}
#Override
public MetaEntry<T> remove(MetaEntry<T> entry) {
list.remove(entry);
return this;
}
#Override
public Iterator<MetaEntry<T>> iterator() {
return list.iterator();
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("<" + name + ">");
for(MetaEntry<T> metaEntry : this) {
builder.append(metaEntry.toString());
}
builder.append("</" + name + ">");
return builder.toString();
}
}
public static void main(String[] args) throws Exception {
MetaEntry<String> compositeMetaEntry = new CompositeMetaEntry<String>();
compositeMetaEntry.setName("File");
compositeMetaEntry.add(
new CompositeMetaEntry<String>().setName("Meta").add(
new SimpleMetaEntry<String>().setName("Generator").setValue("default")
).add(
new SimpleMetaEntry<String>().setName("HeaderHash").setValue("110EbosCOut9ooqtIza4yHdT9xx+wUAp1VMfPqpQKwM=")
).add(
new SimpleMetaEntry<String>().setName("Color")
).add(
new CompositeMetaEntry<String>().setName("MemoryProtection").add(
new SimpleMetaEntry<String>().setName("ProtectTitle").setValue("False")
).add(
new SimpleMetaEntry<String>().setName("ProtectUserName").setValue("False")
).add(
new SimpleMetaEntry<String>().setName("ProtectPassword").setValue("True")
).add(
new SimpleMetaEntry<String>().setName("ProtectURL").setValue("False")
).add(
new SimpleMetaEntry<String>().setName("ProtectNotes").setValue("false")
)
).add(
new SimpleMetaEntry<String>().setName("CustomIcons")
).add(
new SimpleMetaEntry<String>().setName("Binaries")
).add(
new SimpleMetaEntry<String>().setName("CustomData")
)
);
System.out.println(compositeMetaEntry);
}
I have two classes which pretty much implement the same operations for two different numeric types (except for the getHexadecimalValue() method):
public class IntegerType
{
private int value;
public IntegerType()
{
value = 0;
}
public void setValue(int value)
{
this.value = value;
}
public int getValue()
{
return value;
}
public String getHexadecimalValue()
{
int integerValue = (int) getValue();
String hexadecimal = ValueConversions.toHexadecimal(integerValue);
return hexadecimal;
}
}
and
public class FloatingPointType
{
private float value;
public FloatingPointType()
{
value = 0;
}
public void setValue(float value)
{
this.value = value;
}
public float getValue()
{
return value;
}
public String getHexadecimalValue()
{
float floatingValue = (float) getValue();
int intBits = Float.floatToRawIntBits(floatingValue);
return ValueConversions.toHexadecimal(intBits);
}
}
I'm wondering what the best way would be to reduce this redundancy by e.g. defining a superclass called NumberType like this:
public abstract class NumberType
{
protected Number value;
public NumberType()
{
setValue(0);
}
public void setValue(Number value)
{
this.value = value;
}
public Number getValue()
{
return value;
}
public abstract String getHexadecimalValue();
}
Now the problem is that any number can be passed to my inheriting classes but I only want to accept ints and floats respectively while still keeping redundancy to a minimum:
public class IntegerType extends NumberType
{
#Override
public String getHexadecimalValue()
{
// Crashes on runtime if the value doesn't happen to be of the expected type
int integerValue = (int) getValue();
String hexadecimal = ValueConversions.toHexadecimal(integerValue);
return hexadecimal;
}
}
Can this be done by still keeping proper type checking?
You can try this way.
public abstract class NumberType<T extends Number> {
protected T value;
public NumberType(T value) {
this.value = value;
}
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public abstract String getHexadecimalValue();
}
public class FloatingPointType extends NumberType<Float> {
public FloatingPointType() {
super(0f);
}
public String getHexadecimalValue() {
return ValueConversions.toHexadecimal(Float.floatToRawIntBits(value));
}
}
Note: Float and Integer, both class has static toHexString methods which you can directly use if you are comfortable to use them.
public static String toHexString(float f)
public static String toHexString(int i)
This can be done with overloading
for example:
public abstract class NumberType
{
private Number value;
public NumberType()
{
setValue(0);
}
public void setValue(float value)
{
this.value = value;
}
public void setValue(int value)
{
this.value = value;
}
public Number getValue()
{
return value;
}
public abstract String getHexadecimalValue();
}
You can also add then:
public int getIntValue()
{
return value.intValue();
}
public float getFloatValue()
{
return value.floatValue();
}
Ideally, setValue(Number value) must not allow entering any value but float in FloatingPointType and setValue(Number value) must not allow entering any value but int in IntegerType. You can check by using intValue() and floatValue() methods in class Number and throw exception if inappropriate value entered. Number class methods
It would be something like this in setValue(Number value) of IntegerType
if(value.intValue()!= value)
throw new IllegalArgumentException()
I am trying to iterate through an object that I have created and change some of its properties by using a get/set method. I managed to make it work when I only had one object, but now I have objects that inherit the parent object and each have slightly different properties that I want to change. E.g. a String, Float, Integer, Double object. At runtime I will not know which object will be found, so I want my Android application to be able to find it via a unique address and change the properties in the specific inherited object by iterating through the parent object. Please help me with this problem if anyone can. Thank you in advance.
Here is the parent object class code:
public class DataObject
{
private byte[] address;
private String type;
private boolean updatedFlag;
private boolean editedFlag;
public DataObject()
{
updatedFlag = false;
editedFlag = false;
}
public void setAddress(byte[] address)
{
this.address = address;
}
public void setType(String type)
{
this.type = type;
}
public void setUpdatedFlag(boolean updatedFlag)
{
this.updatedFlag = updatedFlag;
}
public void setEditedFlag(boolean editedFlag)
{
this.editedFlag = editedFlag;
}
public byte[] getAddress()
{
//return Arrays.toString(address);
return address;
}
public String getType()
{
return type;
}
public boolean getUpdatedFlag()
{
return updatedFlag;
}
public boolean getEditedFlag()
{
return editedFlag;
}
}
Here is one of the inherited object class:
public class DoubleDataObject extends DataObject
{
private double value;
private String range;
public DoubleDataObject()
{
}
public void setValue(double value)
{
this.value = value;
}
public void setRange(String range)
{
this.range = range;
}
public double getValue()
{
return value;
}
public String getRange()
{
return range;
}
}
And here is the code that iterates through the objects to change their properties:
private void setUpValues(byte[] address, byte[] value)
{
byte[] addressByteArray = address;
Iterator<DataObject> it = dataObjects.iterator();
while(it.hasNext())
{
DataObject currentDataObject = it.next();
byte[] dataObjectByteArray = currentDataObject.getAddress();
if(addressByteArray[0] == dataObjectByteArray[0])
{
System.out.println("Found subsystem!");
if(addressByteArray[1] == dataObjectByteArray[1])
{
System.out.println("Found highlevel!");
if(addressByteArray[2] == dataObjectByteArray[2])
{
System.out.println("Found low level!");
System.out.println("Found data object!");
currentDataObject.setValue(value);
currentDataObject.setUpdatedFlag(true);
System.out.println("Data Object Address: " + Arrays.toString(currentDataObject.getAddress()));
System.out.println("Data Object Type: " + currentDataObject.getType());
System.out.println("Data Object Value: " + currentDataObject.getValue());
System.out.println("Data Object Range: " + currentDataObject.getRange());
System.out.println("Data Object Updated Flag: " + currentDataObject.getUpdatedFlag());
System.out.println("Data Object Edited Flag: " + currentDataObject.getEditedFlag());
}
else
{
System.out.println("CANNOT FIND DATA OBJECT!");
}
}
else
{
System.out.println("CANNOT FIND HIGH LEVEL!");
}
}
else
{
System.out.println("CANNOT FIND SUBSYSTEM!");
}
}
}
You can check which class an object is and cast it to the subclass to access the methods,
is that waht you want to achieve?
DataObject currentDataObject = it.next();
if(currentDataObject instanceof DoubleDataObject){
DoubleDataObject doubleData = (DoubleDataObject) currentDataObject;
//check your methods
}
You can use this :
if (currentDataObject.getClass().equals(DoubleDataObject.class)) {
DoubleDataObject currentDoubleDataObject = (DoubleDataObject)currentDataObject;
currentDoubleDataObject .setValue(1.4d);
}
To test if the currentDataObject is a DoubleDataObject (and not a class inherit from a DoubleDataObject )
i am trying to use the following code...
The Enum class i am using is
public enum AccountType {
kAccountTypeAsset(0x1000),
kAccountTypeAssetFixed(0x1010),
private int value;
private AccountType(int value)
{
this.value = value;
}
public int getValue()
{
return value;
}
}
public AccountType accountType = kAccountTypeAsset;
integerToDB(accountType);
...
/*************************/
public Object integerToDB (Integer i )
{
if(i == -1)
{
return null;
}
return i;
}
How can i use
accountType
as integer.
integerToDB(accountType.getValue()); ?
Since your enum has implemented a getValue method, you can use accountType.getValue() to get the integer value stored in accountType.