Failed to serialize enum value by predefined value - java

I have the following enum:
public enum ChangeMode {
None(1), Add(2), Update(3), Delete(4);
// String value
public String getStringValue() {
return name();
}
public static ChangeMode getEnumValue(String v) {
return valueOf(v);
}
public static ChangeMode getEnumValue(int intValue) {
for (ChangeMode x : values())
if (Objects.equals(x.intValue, intValue))
return x;
return null;
}
// Int value
private int intValue;
private ChangeMode(int intValue) {
this.intValue = intValue;
}
public int getIntValue() {
return this.intValue;
}
}
Notice the enum values start from 1-4 and not 0-3.
I'm using Wildfly and Jackson.
When I'm getting the value 4 from the client JSON (using HTTP POST) I'm getting the following error:
Can not construct instance of com.ta9.enums.ChangeMode from number
value (4): index value outside legal index range [0..3] at [Source:
org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream#55a6e779;
line: 770, column: 26] (through reference chain:

Related

How do I convert an integer to an enum in MyBatis?

I have the following:
public class Stat {
public enum HitType {
MOBILE1(0), MOBILE2(1), DESKTOP(2);
public final int value;
public int value() { return value; }
HitType(int val) {
value = val;
}
public static HitType parseInt(int i) {
switch (i) {
case 0: return MOBILE1;
case 1: return MOBILE2;
case 2: return DESKTOP;
default: return null;
}
}
}
public HitType hitType;
public long sourceId;
public Stat(... int hitType, BigInteger sourceId) {
this.hitType = HitType.parseInt(hitType);
this.sourceId = sourceId.longValueExact();
#Mapper
public interface StatMapper {
#Select("select * from stats where id = #{id}")
#Results(value = {
#Result(property = "hitType", column = "hit_type"),
...
})
public Stat findById(#Param("id") long id);
Stat s = statMapper.findById(1);
response.getOutputStream().print(s.toString());
It still gives this error:
Resolved exception caused by Handler execution: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'hit_type' from result set.
Cause: java.lang.IllegalArgumentException: No enum constant com.company.app.model.Stat.HitType.2
I tried http://stackoverflow.com/questions/5878952/ddg#5878986 and read Convert integer value to matching Java Enum.
If I change the constructor signature to
public Stat(..., int hitType, long sourceId) {
this.sourceId = sourceId;
Then it gives the error
nested exception is org.apache.ibatis.executor.ExecutorException: No constructor found in com.company.app.model.Stat matching [java.math.BigInteger, java.lang.String, java.sql.Timestamp, java.lang.Integer, java.math.BigInteger]
So it seems in the first case it may be setting properties directly, while in the 2nd case, it is using the constructor.
I tried putting HitType hitType in the constructor signature, but it still gives me the No constructor found... error.
MyBatis 3.4.5, MyBatis-Spring 1.3.1, Spring-Boot 1.5.13
I added the getter & setter for that type
public HitType getHitType() {
return hitType;
}
public void setHitType(int hitType) {
this.hitType = HitType.parseInt(hitType);
}
And then it started working. Which is weird because it was complaining about the constructor signature. If it is using the constructor, why would it need the getters and setters?

The Constructor is undefined? Enum error

public Tipo getTipo() {
return this.Importo < 0.0 ? Tipo.USCITA : Tipo.ENTRATA;
}
public int compareTo(Movimento m) {
if (this.idConto != this.idConto) {
return this.idConto - this.idConto;
}
return this.DataMov.compareTo(this.DataMov);
}
public static enum Tipo {
ENTRATA,// here i have this error : The constructor Movimento.Tipo() is undefined
USCITA;// here is the same : The constructor Movimento.Tipo() is undefined
private Tipo(String string2, int n2) {
}
}
I already have constructor that I need, what else I need to write?
I am not sure how do you want to define enum. There are basically 2 solutions to this:
1. Define no parameter enum
public static enum Tipo {
ENTRATA,
USCITA;
}
2. Define enum with parameters
public static enum Tipo {
ENTRATA("Entrata", 1),
USCITA("Uscita", 2);
private String string;
private int integer;
private Tipo(String string, int integer) {
this.string = string;
this.integer = integer;
}
}
You wrote a constructor that takes two arguments, but no default constructor. That means the compiler will not provide a no-arg constructor. You should provide one or remove the private constructor.
I see no reason for the private constructor with two arguments. You don't have any private data members in your enum.
Why is your enum static? Remove that.
public enum Tipo {
ENTRATA, USCITA;
}
You are written wrong enum.
public enum abc {
ENTRATA("abc", 1),// here i have this error : The constructor Movimento.Tipo() is undefined
USCITA("xyz", 2);// here is the same : The constructor Movimento.Tipo() is undefined
private abc(String string2, int n2) {
}
}

Looking up enum label by value

I have the following enum in my java android application:
static enum PaymentType
{
Scheme(0), Topup(1), Normal(2), Free(3), Promotion(4), Discount(5), Partial(6),
Refund(7), NoShow(8), Prepay(9), Customer(10), Return(11), Change(12), PettyCash(13),
StateTax(14), LocalTax(15), Voucher(16), Membership(17), Gratuity(18), Overpayment(19),
PrepayTime(20), HandlingFee(21);
private int value;
private PaymentType(int i) {
value = i;
}
public int getValue() {
return value;
}
}
I use this enum alot to find out the integer value of one of these string labels, for example int i = Lookups.PaymentType.Voucher.getValue();.
How can I do this the other way around? I have an integer value from a database and I need to find which string that corresponds to.
You should do something like this (static-init block should be at the end! and in your case just replace "asc" and "desc" with numbers, or add any other field):
public enum SortOrder {
ASC("asc"),
DESC("desc");
private static final HashMap<String, SortOrder> MAP = new HashMap<String, SortOrder>();
private String value;
private SortOrder(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
public static SortOrder getByName(String name) {
return MAP.get(name);
}
static {
for (SortOrder field : SortOrder.values()) {
MAP.put(field.getValue(), field);
}
}
}
After that, just call:
SortOrder asc = SortOrder.getByName("asc");
To go from an ordinal() index value back to enum:
type = PaymentType.values()[index];
However, keep in mind that this is fragile when the ordinal is stored anywhere else, such as a database. If the index numbers ever change, you'll get invalid results.
For more reliable lookup table, use a Map.

How can the type of a bean property be null?

In the book "Thinking in Java" there is an example of how to get information for a bean via Reflection/Introspection.
BeanInfo bi = Introspector.getBeanInfo(Car.class, Object.class);
for (PropertyDescriptor d: bi.getPropertyDescriptors()) {
Class<?> p = d.getPropertyType();
if (p == null) continue;
[...]
}
In line 4 of that sample above there is a check if the PropertyType is null. When and under what circumstances does that happen? Can you give an example?
From the JavaDoc:
Returns null if the type is an indexed property that does not support
non-indexed access.
So I guess if the property type is an indexed property(like an array) it will return null.
The Javadoc for the getPropertyType method of the PropertyDescriptor class states:
The result may be "null" if this is an indexed property that does not
support non-indexed access.
Indexed properties are those that are backed by an array of values. In addition to the standard JavaBean accessor methods, indexed properties may also have methods to get/set individual elements in the array, by specifying an index. The JavaBean, may therefore, have the indexed getters and setters:
public PropertyElement getPropertyName(int index)
public void setPropertyName(int index, PropertyElement element)
in addition the standard getter and setter for non-indexed access:
public PropertyElement[] getPropertyName()
public void setPropertyName(PropertyElement element[])
Going by the Javadoc description, if you omit the non-indexed accessors, you can obtain a return value of null for the property type of the property descriptor.
So, if you have a JavaBean of the following variety, you could get a null return value:
class ExampleBean
{
ExampleBean()
{
this.elements = new String[10];
}
private String[] elements;
// standard getters and setters for non-indexed access. Comment the lines in the double curly brackets, to have getPropertyType return null.
// {{
public String[] getElements()
{
return elements;
}
public void setElements(String[] elements)
{
this.elements = elements;
}
// }}
// indexed getters and setters
public String getElements(int index) {
return this.elements[index];
}
public void setElements(int index, String[] elements)
{
this.elements[index] = elements;
}
}
Note, while that you can implement the indexed property accessors alone, it is not recommended to do so, as the standard accessors are used to read and write values, if you happen to use the getReadMethod and getWriteMethod methods of the PropertyDescriptor.
This returns null when you have a method like int getValue(int index).
The following code prints
double is null
ints class [I
The class:
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
public class BeanInfos {
public static void main(String[] args) {
try {
BeanInfo bi = Introspector.getBeanInfo(ClassA.class, Object.class);
for (PropertyDescriptor d : bi.getPropertyDescriptors()) {
Class<?> p = d.getPropertyType();
if (p == null)
System.out.println(d.getName() + " is null" );
else
System.out.println(d.getName() + " " + p);
}
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
}
class ClassA {
private int[] ints;
private double[] doubles;
public int[] getInts() {
return ints;
}
public void setInts(int[] ints) {
this.ints = ints;
}
public double getDouble(int idx) {
return doubles[idx];
}
public void setDoubles(double val, int idx) {
this.doubles[idx] = val;
}
}

enum type with numeric constant

I'm getting data from a legacy system where a certain one byte field is a code that may contain a letter or a number. I want to map it to an enum but I'm not sure how to handle the numeric values.
public enum UsageCode {
A ("Antique"),
F ("Flood Damaged"),
N ("New");
// 0 ("Unknown") How to allow for value of "0"?
private final String description;
UsageCode(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
Turn it inside out:
public enum UsageCode {
ANTIQUE ('A'),
FLOOD_DAMAGED ('F'),
NEW ('N');
UNKNOWN ('0')
private static final Map<Character, UsageCode> charToEnum
= new HashMap<Character, UsageCode>();
static { // Initialize map from legacy code to enum constant
for (UsageCode code : values())
charToEnum.put(code.getCode(), code);
}
// Returns UsageCode for legacy character code, or null if code is invalid
public static UsageCode fromLegacyCode(char code) {
return charToEnum.get(code);
}
private final char code;
UsageCode(char code) {
this.code = code;
}
public char getCode() {
return code;
}
}
For converting the incoming character codes into enum values, I added an inner Map<Character, UsageCode> and a static conversion method.
Example adapted from Effective Java 2nd Edition, Item 30.
You can do it other way round, having a meaningful constant and storing legacy value representation:
public enum UsageCode {
ANTIQUE("A"),
FLOOD_DAMAGED("F"),
NEW("N"),
UNKNOWN("0");
private String legacy;
private UsageCode(String legacy) {
this.legacy = legacy;
}
public static UsageCode toUsageCode(String legacyOutput) {
for(UsageCode code : values()) {
if (code.legacy.equals(legacyOutput)) {
return code;
}
}
return null;
}
}

Categories

Resources