Deserializing json response to custom enum value in java - java

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

Related

creat an enumeration that containt Integer variables

I want to create an enumeration that containt Integer variables , the result is needed to be something like this :
#AllArgsConstructor
#Getter
public enum Test {
1("Test1"),
2("Test2");
private final String value;
}
As far as I know there is no such thing like this in Java.
If you really need enum for that, you can do it in reverse:
public enum TestEnum {
TEST_1(1),
TEST_2(2);
private final int value;
TestEnum(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}

Jackson serializes Enum to NAME not value (XML) Java

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());

Enum with negative/gap value in Java

I have a problem with enum in Java. I have an enum that starts from -1:
public enum AipType {
Unknown(-1),
None(0),
AipMod(1),
AipNoMod(2);
private final int id;
AipType(int id) {this.id = id;}
public int getValue() {return id;}
}
The problem is when I use this code to initialize a var of AipType
AipType at = AipType.getValues()[index];
where index is a number in the interval [-1,0,1,2] the -1 mess up the value.
i.e. 0 returns Unknown, 1 returns AipMod and 2 returns AipNoMod.
I used this implementation because I need to set manually the numeric value for each enum case. In other case I have a gap beetwen the values so I have the same problem: I cannot use values() and then access with [ ].
I tried to initialize in this way
AipType at = AipType(index);
but doesn't work.
Ideas ? Thanks...
We don't know what the getValues() method you're using exactly doing. Is it supposed to be values().
Anyway, you can always add a static method in your enum, which returns the correct enum instance for that value, and invoke it wherever you need it:
public enum AipType {
Unknown(-1),
None(0),
AipMod(1),
AipNoMod(2);
private final int id;
AipType(int id) {this.id = id;}
public int getValue() {return id;}
public static AipType fromValue(int id) {
for (AipType aip: values()) {
if (aip.getValue() == id) {
return aip;
}
}
return null;
}
}
If you're invoking fromValue() too often, you might also want to cache the array returned by values() inside the enum itself, and use it. Or even better, a map would be a better idea.
Enum.getValues() returns an array of the enums based on the definition order in the enum class.
getValues() doesn't know about the id field or the getValue() method you have added to your enum.
What you could do instead of calling getValues()[-1] (by the way, you'll never be able to index an array in Java with -1) is to add a static function like:
static AipType getAipType(int id) {
for (AipType a : getValues()) {
if (a.getId() == id) return a;
}
throw new IllegalArgumentException("id=" + id + " does not exist");
}
Just have a Map<Integer, AipType> instead of using values(), and expose access to it via a method:
public enum AipType {
UNKNOWN(-1),
NONE(0),
MOD(1),
NO_MOD(2);
private static final Map<Integer, AipType> VALUE_TO_ENUM_MAP;
private final int value;
static {
VALUE_TO_ENUM_MAP = new HashMap<>();
for (AipType type : EnumSet.allOf(AipType.class)) {
VALUE_TO_ENUM_MAP.put(type.value, type);
}
}
private AipType(int value) {
this.value = value;
}
public int getValue() {
return id;
}
public static AipType forValue(int value) {
return VALUE_TO_ENUM_MAP.get(value);
}
}
That will be completely flexible about values - or you could still use an array and just offset it appropriately.
Can you declare your enum like below?
public enum AipType {
Unknown(-1),None(0),AipMod(1),AipNoMod(2);
private int value;
private AipType(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
public static AipType fromValue(int value) {
for (AipType at: values()) {
if (at.getValue() == value) {
return at;
}
}
return null;
}
};
And instantiate like:
AipType at = AipType.fromValue(-1);
If the ids are completely custom, the only chance you'd have would be to create a map and store the id->AipType mapping there.
Example:
public enum AipType {
... //enum definitions here
static Map<Integer, AipType> map = new HashMap<>();
static {
for( AipType a : AipType.values() ) {
map.put(a.id, a);
}
}
public static AipType typeById( int id ) {
return map.get(id);
}
}
Then call it like AipType.typeById(-1);.

Enum type conversion to int

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.

How can I declare enums using java

I want to convert this sample C# code into a java code:
public enum myEnum {
ONE = "one",
TWO = "two",
};
Because I want to change this constant class into enum
public final class TestConstants {
public static String ONE = "one";
public static String TWO= "two";
}
public enum MyEnum {
ONE(1),
TWO(2);
private int value;
private MyEnum(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
In short - you can define any number of parameters for the enum as long as you provide constructor arguments (and set the values to the respective fields)
As Scott noted - the official enum documentation gives you the answer. Always start from the official documentation of language features and constructs.
Update: For strings the only difference is that your constructor argument is String, and you declare enums with TEST("test")
enums are classes in Java. They have an implicit ordinal value, starting at 0. If you want to store an additional field, then you do it like for any other class:
public enum MyEnum {
ONE(1),
TWO(2);
private final int value;
private MyEnum(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
Quite simply as follows:
/**
* #author The Elite Gentleman
*
*/
public enum MyEnum {
ONE("one"), TWO("two")
;
private final String value;
private MyEnum(final String value) {
this.value = value;
}
public String getValue() {
return value;
}
#Override
public String toString() {
// TODO Auto-generated method stub
return getValue();
}
}
For more info, visit Enum Types from Oracle Java Tutorials. Also, bear in mind that enums have private constructor.
Update, since you've updated your post, I've changed my value from an int to a String.
Related: Java String enum.
Well, in java, you can also create a parameterized enum. Say you want to create a className enum, in which you need to store classCode as well as className, you can do that like this:
public enum ClassEnum {
ONE(1, "One"),
TWO(2, "Two"),
THREE(3, "Three"),
FOUR(4, "Four"),
FIVE(5, "Five")
;
private int code;
private String name;
private ClassEnum(int code, String name) {
this.code = code;
this.name = name;
}
public int getCode() {
return code;
}
public String getName() {
return name;
}
}
public enum MyEnum
{
ONE(1),
TWO(2);
private int value;
private MyEnum(int val){
value = val;
}
public int getValue(){
return value;
}
}
public enum NewEnum {
ONE("test"),
TWO("test");
private String s;
private NewEnum(String s) {
this.s = s);
}
public String getS() {
return this.s;
}
}

Categories

Resources