spring-data-cassandra unable to convert enum - java

I'm trying to have spring-data convert my enum type to and int field in cassandra but I'm getting the following exception:
Unexpected runtime exception java.lang.IllegalArgumentException:
Value 2 of type class com.twc.atg.td.dbo.client.ClassCode does not correspond to any CQL3 type
Here is the piece of code I'm using:
#Enumerated(EnumType.ORDINAL)
#Column("class_code")
public ClassCode classCode;

Since it is not supported by spring-data-cassandra, you can implement this logic in getters/setters.
#Table
public class Writer {
...
public enum WriterType {
POET, DETECTIVE, JOUNALIST
}
...
#Column(value = "writer_type")
private Integer writerType;
...
public WriterType getWriterType() {
return WriterType.values()[writerType];
}
public void setWriterType(WriterType writerType) {
this.writerType = writerType.ordinal();
}

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?

Setter issue while converting JSON to Java Object

I'm trying to convert below simple JSON to Java Object using com.fasterxml.jackson.core. I have problem with bonusAmount field setter method.
JSON:
{"amount":332.5, "bonusamount":3, "action":"Spend"}
Java class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class GameRequest {
#JsonProperty("amount")
private BigDecimal amount;
#JsonProperty("bonusamount")
private BigDecimal bonusAmount;
#JsonProperty("action")
private String action;
.....
public BigDecimal getBonusAmount() {
return bonusAmount;
}
public void setBonusAmount(BigDecimal bonusAmount) {
this.bonusAmount = bonusAmount;
}
Value of bonusAmount field is NULL when I try to use it but if I change name of setter method from setBonusAmount to setBonusamount then it works. Can someone tell me why??
That is because you have renamed your field using #JsonProperty("bonusamount") that means Jackson searches for a method named setBonusamount (first char toUpperCase, rest stays the same)

Empty column values mapping to java enum using ORMlite

How do I map empty or unknown values to the enum in java. I am using Ormlite.
#DatabaseField(canBeNull=false, columnName=COLUMN_NAME_DEVICE_TYPE,
dataType=DataType.ENUM_STRING)
private DeviceType deviceType;
And here is my enum
public enum DeviceType {
iPhone, iPad, Android,
OSX, Windows, Windows8,
WP7, WP8, Blackberry,
Browser, Facebook, Unknown;
#JsonCreator
public static DeviceType parse(String s) {
for (DeviceType t : values()) {
if (t.name().toLowerCase().equals(s)) {
return t;
}
}
return Unknown;
}
#JsonValue
#Override
public String toString() {
return name().toLowerCase();
}
}
Am always getting the following exception:
Caused by: java.sql.SQLException: Cannot get enum value of '' for field FieldType:name=deviceType,class=MyEntity
Take a look on data in database. I guess that this row has empty string '' for which no enum exists.

Unmarshal XML to different objects depending on Attribute using JAXB [duplicate]

This question already has answers here:
JAXB: how to unmarshal a List of objects of different types but with common parent?
(3 answers)
Closed 7 years ago.
I am trying to unmarshal the following XML:
<calcElement partname="driver">
<driverXs>300.00</driverXs>
<seq>1</seq>
</calcElement>
<calcElement partname="ratingData">
<baseMiles>6000</baseMiles>
<vehicleGroup>15</vehicleGroup>
<documentVersion>4</documentVersion>
</calcElement>
I have the following classes, which represent the 2 above instances of calcElement:
public abstract class CalcElement {
private String partName;
#XmlAttribute
public String getPartName() {
return partName;
}
public void setPartName(String partName) {
this.partName = partName;
}
}
public class DriverCalcElement extends CalcElement {
private String driverXs;
private String seq;
public String getDriverXs() {
return driverXs;
}
public void setDriverXs(String driverXs) {
this.driverXs = driverXs;
}
public String getSeq() {
return seq;
}
public void setSeq(String seq) {
this.seq = seq;
}
}
public class RatingDataCalcElement extends CalcElement {
private String baseMiles;
private String vehicleGroup;
private String documentVersion;
public String getBaseMiles() {
return baseMiles;
}
public void setBaseMiles(String baseMiles) {
this.baseMiles = baseMiles;
}
public String getVehicleGroup() {
return vehicleGroup;
}
public void setVehicleGroup(String vehicleGroup) {
this.vehicleGroup = vehicleGroup;
}
public String getDocumentVersion() {
return documentVersion;
}
public void setDocumentVersion(String documentVersion) {
this.documentVersion = documentVersion;
}
}
However I am unable to work out the combination of Annotations to add to the classes to successfully unmarshal (and marshal) this code.
What do I need to add to the classes to get this to work?
What you're trying to do isn't supported natively by JAXB. XML Schema 1.1 introduced the concept of a type alternative which you could use for determining the type of your element with an XPath expression, using the value of attributes on that element, but this isn't supported by JAXB 2.x (which is based on XML Schema 1.0).
You can do something similar with JAXB using xsi:type, but you would either need to change your document on disk or do a transform (e.g. using XSLT) to include the xsi:type attribute before passing it to the JAXB Unmarshaller. The values of xsi:type would be the type names you assign with your annotations. See the #XmlType annotation for how the type names of your classes are computed.

get inside setter information about instance variable name

Is it possible to get the variable name of the current instance in the object's setter?
Something like this
public class Class {
private DataType dataType;
}
public class DataType {
public void setValue(String value) {
if (variableName is 'dataType') {
this.value = value;
} else {
this.value = null;
}
}
}
If it's not possible using standard utilities then it's possible to create some kind of annotation to store there variable name and then use it in setter?
When I try to do like this - the annotation is null.
I create annotation
#Retention(RetentionPolicy.CLASS)
#Target(ElementType.FIELD)
public #interface FieldName {
String fieldName();
}
Then I add it to field
public class Class {
#FieldName(fieldName = "dataType")
private DataType dataType;
}
And when I try to get it in the getter of DataType - the annotation FieldName is null.
private String wrapGetter(String requiredFieldName, String dataTypeField) {
FieldName fieldName = this.getClass().getAnnotation(FieldName.class);
if (fieldName.fieldName().equals(requiredFieldName)) {
return dataTypeField;
} else {
return dataTypeField;
}
}
There are a few problems with what you are trying to do:
Your RetentionPolicy is set it to CLASS which means that class loader will discard it and it will not be available at runtime. You should use RetentionPolicy.RUNTIME instead.
this.getClass().getAnnotation(FieldName.class) will give you the class annotation.
In the below example the annotation is not null and you can get "example" string in setValue method:
#FieldName(fieldName = "example")
public class DataType {
public void setValue(String value) {
System.out.println(this.getClass().getAnnotation(FieldName.class));
}
}
public static void main(String[] args) {
new DataType().setValue("ignored");
}
This also requires to change the target of your annotation to #Target(ElementType.TYPE).
Variable or field name is just a reference, it points to some object in the memory. You can have multiple references to the same object. Although you can annotate fields in different classes, it will be a problem with local variables and parameters - it is difficult to say as I don't know what you are trying to achieve.
Problematic example:
public class ClassOne {
#FieldName(fieldName = "dataType")
private DataType a;
}
public class ClassTwo {
#FieldName(fieldName = "dataType")
private DataType b;
}
public class ClassThree {
public void doSomething() {
DataType c = new DataType();
}
}
public class ClassFour {
public void doSomething(DataType d) {
// ...
}
}
Generally, it all comes down to the problem that the instance of the class has no information about how it is being referred to. However, for the field, enclosing class has this information. Consider moving your method into that class. And you can handle this without any annotations:
public class DataType {
public void setValue(String value) {
// ...
}
}
public class ClassOne {
private DataType dataType;
public void setDataTypeValue(String value) {
dataType.setValue(value);
}
}
public class ClassTwo {
private DataType anyOtherFieldName;
public void setDataTypeValue(String value) {
anyOtherFieldName.setValue(null);
}
}
The setter that sets null and ignores the parameter is very misleading, your IDE should be giving you a warning about unused parameter, it's not without a reason. I think you should consider a redesign, but I cannot advice you further without knowing more details.
Instead of solving the problem, try to solve the cause of that problem.
Use #Retention(RetentionPolicy.RUNTIME)
Replace this
FieldName fieldNameAnnotation = field.getAnnotation(FieldName.class);
With this
Field field = this.getClass().getField("dataType");
FieldName fieldName = field.getAnnotation(FieldName.class);

Categories

Resources