I have a class called BalanceTarget
public class BalanceTarget {
#JsonProperty("amount")
private String amount;
public enum CreditDebitIndicatorEnum {
CREDIT("Credit"),
DEBIT("Debit");
private String value;
CreditDebitIndicatorEnum(String value) {
this.value = value;
}
#JsonValue
public String getValue() {
return value;
}
#Override
public String toString() {
return String.valueOf(value);
}
#JsonCreator
public static CreditDebitIndicatorEnum fromValue(String value) {
for (CreditDebitIndicatorEnum b : CreditDebitIndicatorEnum.values()) {
if (b.value.equals(value)) {
return b;
}
}
throw new IllegalArgumentException("Unexpected value '" + value + "'");
}
}
#JsonProperty("creditDebitIndicator")
private CreditDebitIndicatorEnum creditDebitIndicator;
//getter and setters
}
Another class BalanceSource
public class BalanceSource {
#JsonProperty("amount")
private String amount;
public enum CreditDebitIndicatorEnum {
C("C"),
D("D");
private String value;
CreditDebitIndicatorEnum(String value) {
this.value = value;
}
#JsonValue
public String getValue() {
return value;
}
#Override
public String toString() {
return String.valueOf(value);
}
#JsonCreator
public static CreditDebitIndicatorEnum fromValue(String value) {
for (CreditDebitIndicatorEnum b : CreditDebitIndicatorEnum.values()) {
if (b.value.equals(value)) {
return b;
}
}
throw new IllegalArgumentException("Unexpected value '" + value + "'");
}
}
#JsonProperty("creditDebitIndicator")
private CreditDebitIndicatorEnum creditDebitIndicator;
//getter and setters
}
I have a mapper for Balance
#Mapper(componentModel = "spring", uses = CreditDebitIndicatorMapper.class)
public interface BalanceMapper {
BalanceTarget convert(BalanceSource a);
}
I have another mapper for CreditDebitIndicator
#Mapper(componentModel = "spring")
public interface CreditDebitIndicatorMapper {
#ValueMapping(source = "C", target = "CREDIT")
#ValueMapping(source = "D", target = "DEBIT")
BalanceTarget.CreditDebitIndicatorEnum convert(BalanceSource.CreditDebitIndicatorEnum a);
}
On building the code it gives out this error
The following constants from the property
"BalanceSource.CreditDebitIndicatorEnum
balances[].creditDebitIndicator" enum have no corresponding constant
in the "BalanceTarget.CreditDebitIndicatorEnum
balances[].creditDebitIndicator" enum and must be be mapped via adding
additional mappings: C, D.
Related
I'm writing annotated model classes for json serialization/deserialization using jackson.
I have a json that contains a map, where the key is an enum and the value can be different types (including arrays) depending on key value.
A simplified example, this is what I need:
{
"key1": "string value",
"key2": [{"id":"1", "value": "test1"}, {"id":"2", "value": "test2"}]
}
I have tried, and I get this:
{
"KEY1": {"value": "string value"},
"KEY2": {"list": [{"id": "1", "value": "test1"}, {"id": "2", "value": "test2"}]}
}
So, unwrapping does not work.
Could anyone tell me what I am doing wrong ?
Here is the code:
public class Main {
public static void main(String[] args) throws Exception {
HashMap<Keys, ValueType> map = new HashMap<>();
map.put(Keys.KEY1, new StringValue("string value"));
map.put(Keys.KEY2, new ListValue( Arrays.asList(new Element[] {
new Element("1", "test1"),
new Element("2", "test2")
} )));
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(map);
System.out.println(s);
}
}
public enum Keys {
KEY1("key1"),
KEY2("key2");
private String value;
Keys(String s) {
this.value = s;
}
}
public interface ValueType {
}
public class StringValue implements ValueType {
#JsonUnwrapped
private String value;
public StringValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public class ListValue implements ValueType {
#JsonUnwrapped
private List<Element> list;
public ListValue(List<Element> list) {
this.list = list;
}
public List<Element> getList() {
return list;
}
public void setList(List<Element> list) {
this.list = list;
}
}
public class Element {
#JsonProperty
private String id;
#JsonProperty
private String value;
public Element(String id, String value) {
this.id = id;
this.value = value;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
You can annotate the classes' getters methods with the JsonValue annotation that indicates that the value of annotated accessor is to be used as the single value to serialize for the instance, instead of the usual method of collecting properties of value:
public class StringValue implements ValueType {
#JsonUnwrapped
private String value;
public StringValue(String value) {
this.value = value;
}
#JsonValue //<-- added annotation to the original getter method
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public class ListValue implements ValueType {
#JsonUnwrapped
private List<Element> list;
public ListValue(List<Element> list) {
this.list = list;
}
#JsonValue //<-- added annotation to the original getter method
public List<Element> getList() {
return list;
}
public void setList(List<Element> list) {
this.list = list;
}
}
I was asked to make a a column called Type a varchar2(1)which has values partial or all
That what i made in Model.Java
#Column(name="TYPE")
#Enumerated(EnumType.STRING)
public TypeEnum getType() {
return type;
}
public void setType(TypeEnum type) {
this.type = type;
}
And this is my TypeEnum.java
public enum TypeEnum {
ALL(0, "all"),
PARTIAL(1, "partial");
private int code;
private String value;
private TypeEnum(int code, String value) {
this.code = code;
this.value = value;
}
public String getValue() {
return value;
}
public int getCode() {
return code;
}
public static TypeEnum getTypeEnum(String value){
TypeEnum[] types = values();
for(int i=0; i<types.length; i++){
TypeEnum type = types[i];
if(value.equals(type.getValue()))
return type;
}
return null;
}
}
So how to store the TypeEnum in DB to achieve the varchar2(1)
You could use a Converter to map your enums to varchar(1) yourself. Something like:
#Column("TYPE") #Convert(TypeEnumToString.class) TypeEnum type;
with the converter class implemented something like:
public class TypeEnumToString implements AttributeConverter<TypeEnum, String> {
#Override
public TypeEnum convertToEntityAttribute(String value) {
// return conversion;
}
#Override
public String convertToDatabaseColumn(TypeEnum value) {
// return conversion;
}
}
You can achieve this by implementing AttributeConverter<TypeEnum, String>
#Converter
public class TypeEnumConverter implements AttributeConverter<TypeEnum, String> {
#Override
public String convertToDatabaseColumn(TypeEnum attribute) {
return String.valueOf(attribute.getCode());
}
#Override
public TypeEnum convertToEntityAttribute(String dbData) {
return getTypeEnumFromCode(parseInt(dbData));
}
}
getTypeEnumFromCode can be implemented similar to your getTypeEnum method.
Then, define it like
#Column("TYPE")
#Convert(TypeEnumToString.class)
TypeEnum type;
p.s.I just used code from your enum but it can be any other logic too.
I'm familiar with using the builder pattern with generics and subclassing, but I can't see how to make it work with a non-trivial tree of subclasses (i.e. C extends B extends A). Here's a simple example of what I'm trying to do:
class A {
private final int value;
protected A(ABuilder builder) {
this.value = builder.value;
}
public int getValue() { return value; }
public static class ABuilder<T extends ABuilder<T>> {
private int value;
public T withValue(int value) {
this.value = value;
return (T) this;
}
public A build() {
return new A(this);
}
}
}
class B extends A {
private final String name;
public static BBuilder builder() {
return new BBuilder();
}
protected B(BBuilder builder) {
super(builder);
this.name = builder.name;
}
public String getName() { return name; }
public static class BBuilder<U extends BBuilder<U>> extends ABuilder<BBuilder<U>> {
private String name;
public U withName(String name) {
this.name = name;
return (U) this;
}
public B build() {
return new B(this);
}
}
}
Everything is fine if I declare BBuilder without the generic type:
public static class BBuilder extends ABuilder<BBuilder>
Since I want BBuilder to be extended by a CBuilder, I'm trying to use the same sort of Curiously Recurring Template Pattern as ABuilder. But like this, the compiler sees BBuilder.withValue() as returning an ABuilder, not a BBuilder as I want. This:
B b = builder.withValue(1)
.withName("X")
.build();
doesn't compile. Can anyone see what I'm doing wrong here, I've been going round trying different patterns of generics but can't get it to work.
Thanks to anyone who has any advice.
It seems that your mistake only with declaring correct parameter:
class A {
private final int value;
public static <T extends Builder<T>> T builderA() {
return (T)new Builder<>();
}
protected A(Builder<? extends Builder<?>> builder) {
value = builder.value;
}
public static class Builder<T extends Builder<T>> {
private int value;
public T withValue(int value) {
this.value = value;
return (T)this;
}
public A build() {
return new A(this);
}
}
}
class B extends A {
private final String name;
public static <T extends Builder<T>> T builderB() {
return (T)new Builder<>();
}
protected B(Builder<? extends Builder<?>> builder) {
super(builder);
name = builder.name;
}
public static class Builder<T extends Builder<T>> extends A.Builder<T> {
private String name;
public Builder<T> withName(String name) {
this.name = name;
return this;
}
public B build() {
return new B(this);
}
}
}
Client code:
A a = A.builder().withValue(1).build();
B b = B.builder().withValue(2).withName("xx").build();
Are you certain you need generics? This hierarchy seems to work fine without generics.
static class A {
protected final int value;
protected A(ABuilder builder) {
this.value = builder.value;
}
public int getValue() {
return value;
}
#Override
public String toString() {
return "A{" +
"value=" + value +
'}';
}
public static ABuilder builder() {
return new ABuilder();
}
public static class ABuilder {
protected int value;
public ABuilder withValue(int value) {
this.value = value;
return this;
}
public A build() {
return new A(this);
}
}
}
static class B extends A {
protected final String name;
protected B(BBuilder builder) {
super(builder);
this.name = builder.name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return "B{" +
"value=" + value +
", name='" + name + '\'' +
'}';
}
public static BBuilder builder() {
return new BBuilder();
}
public static class BBuilder extends ABuilder {
private String name;
public BBuilder withName(String name) {
this.name = name;
return this;
}
#Override
public BBuilder withValue(int value) {
this.value = value * 2;
return this;
}
public B build() {
return new B(this);
}
}
}
static class C extends B {
private final String otherName;
protected C(CBuilder builder) {
super(builder);
this.otherName = builder.otherName;
}
public String getName() {
return otherName;
}
#Override
public String toString() {
return "C{" +
"value=" + value +
", name='" + name + '\'' +
", otherName='" + otherName + '\'' +
'}';
}
public static CBuilder builder() {
return new CBuilder();
}
public static class CBuilder extends BBuilder {
private String otherName;
public CBuilder withName(String name) {
this.otherName = name;
return this;
}
public C build() {
return new C(this);
}
}
}
public void test() {
A a = A.builder().withValue(10).build();
B b = B.builder().withValue(10).withName("B").build();
C c = C.builder().withName("C").build();
System.out.println("a = "+a);
System.out.println("b = "+b);
System.out.println("c = "+c);
}
I would like to store and retrieve special characters (/, * etc) into/from DB table. This is my attempt:
public enum SpecialCharacters {
Hack("H/K"), Gk("G*M");
private String value;
private SpecialCharacters(String value) {
this.value = value;
}
public String toString() {
return this.value; // This will return , # or +
}
}
#Column(name = "Special_Char")
#Enumerated(EnumType.STRING)
private SpecialCharacters specialCharacters;
...
But in DB table it stores only enum field Names like Hack and Gk, not H/K and G*M
With the #Enumerated Annotation you are only able to store the name or ordinal of your enum. With JPA 2.1 you can use the #Converter Annotation.
See Chapter 11.1.10 of the specification.
Example:
Enum:
public enum SpecialCharacter {
Hack("H/K"),
Gk("G*M");
private String value;
private SpecialCharacter(String value) {
this.value = value;
}
public String toString() {
return this.value; // This will return , # or +
}
public static SpecialCharacter valueOfKey(String key) {
for (SpecialCharacter specialCharacter : values()) {
if (specialCharacter.toString().equals(key)) {
return specialCharacter;
}
}
throw new IllegalArgumentException("Illegal key");
}
}
ConverterClass:
#Converter(autoApply = true)
public class SpecialCharacterConverter implements AttributeConverter<SpecialCharacter, String> {
/**
* Converts a {#link SpecialCharacter} to the correspondig String that is used in the database
*/
#Override
public String convertToDatabaseColumn(SpecialCharacter specialCharacter) {
return specialCharacter.toString();
}
/**
* Converts a String from the database to the corresponding {#link SpecialCharacter}.
*/
#Override
public SpecialCharacter convertToEntityAttribute(String dbValue) {
return SpecialCharacter.valueOfKey(dbValue);
}
}
Entity-Object:
#Entity
public class SomeEntity {
#Column(name = "Special_Char")
private SpecialCharacter specialCharacter;
public SpecialCharacter getSpecialCharacter() {
return this.specialCharacter;
}
public void setSpecialCharacter(SpecialCharacter specialCharacter) {
this.specialCharacter = specialCharacter;
}
}
How can I get the name of a Java Enum type given its value?
I have the following code which works for a particular Enum type, can I make it more generic?
public enum Category {
APPLE("3"),
ORANGE("1"),
private final String identifier;
private Category(String identifier) {
this.identifier = identifier;
}
public String toString() {
return identifier;
}
public static String getEnumNameForValue(Object value){
Category[] values = Category.values();
String enumValue = null;
for(Category eachValue : values) {
enumValue = eachValue.toString();
if (enumValue.equalsIgnoreCase(value)) {
return eachValue.name();
}
}
return enumValue;
}
}
You should replace your getEnumNameForValue by a call to the name() method.
Try below code
public enum SalaryHeadMasterEnum {
BASIC_PAY("basic pay"),
MEDICAL_ALLOWANCE("Medical Allowance");
private String name;
private SalaryHeadMasterEnum(String stringVal) {
name=stringVal;
}
public String toString(){
return name;
}
public static String getEnumByString(String code){
for(SalaryHeadMasterEnum e : SalaryHeadMasterEnum.values()){
if(e.name.equals(code)) return e.name();
}
return null;
}
}
Now you can use below code to retrieve the Enum by Value
SalaryHeadMasterEnum.getEnumByString("Basic Pay")
Use Below code to get ENUM as String
SalaryHeadMasterEnum.BASIC_PAY.name()
Use below code to get string Value for enum
SalaryHeadMasterEnum.BASIC_PAY.toString()
Try, the following code..
#Override
public String toString() {
return this.name();
}
Here is the below code, it will return the Enum name from Enum value.
public enum Test {
PLUS("Plus One"), MINUS("MinusTwo"), TIMES("MultiplyByFour"), DIVIDE(
"DivideByZero");
private String operationName;
private Test(final String operationName) {
setOperationName(operationName);
}
public String getOperationName() {
return operationName;
}
public void setOperationName(final String operationName) {
this.operationName = operationName;
}
public static Test getOperationName(final String operationName) {
for (Test oprname : Test.values()) {
if (operationName.equals(oprname.toString())) {
return oprname;
}
}
return null;
}
#Override
public String toString() {
return operationName;
}
}
public class Main {
public static void main(String[] args) {
Test test = Test.getOperationName("Plus One");
switch (test) {
case PLUS:
System.out.println("Plus.....");
break;
case MINUS:
System.out.println("Minus.....");
break;
default:
System.out.println("Nothing..");
break;
}
}
}
In such cases, you can convert the values of enum to a List and stream through it.
Something like below examples. I would recommend using filter().
Using ForEach:
List<Category> category = Arrays.asList(Category.values());
category.stream().forEach(eachCategory -> {
if(eachCategory.toString().equals("3")){
String name = eachCategory.name();
}
});
Or, using Filter:
When you want to find with code:
List<Category> categoryList = Arrays.asList(Category.values());
Category category = categoryList.stream().filter(eachCategory -> eachCategory.toString().equals("3")).findAny().orElse(null);
System.out.println(category.toString() + " " + category.name());
When you want to find with name:
List<Category> categoryList = Arrays.asList(Category.values());
Category category = categoryList.stream().filter(eachCategory -> eachCategory.name().equals("Apple")).findAny().orElse(null);
System.out.println(category.toString() + " " + category.name());
Hope it helps! I know this is a very old post, but someone can get help.
I believe it's better to provide the required method in the enum itself. This is how I fetch Enum Name for a given value. This works for CONSTANT("value") type of enums.
public enum WalletType {
UPI("upi-paymode"),
PAYTM("paytm-paymode"),
GPAY("google-pay");
private String walletType;
WalletType(String walletType) {
this.walletType = walletType;
}
public String getWalletType() {
return walletTypeValue;
}
public WalletType getByValue(String value) {
return Arrays.stream(WalletType.values()).filter(wallet -> wallet.getWalletType().equalsIgnoreCase(value)).findFirst().get();
}
}
e.g. WalletType.getByValue("google-pay").name()
this will give you - GPAY
enum MyEnum {
ENUM_A("A"),
ENUM_B("B");
private String name;
private static final Map<String,MyEnum> unmodifiableMap;
MyEnum (String name) {
this.name = name;
}
public String getName() {
return this.name;
}
static {
Map<String,MyEnum> map = new ConcurrentHashMap<String, MyEnum>();
for (MyEnum instance : MyEnum.values()) {
map.put(instance.getName().toLowerCase(),instance);
}
unmodifiableMap = Collections.unmodifiableMap(map);
}
public static MyEnum get (String name) {
return unmodifiableMap.get(name.toLowerCase());
}
}
Now you can use below code to retrieve the Enum by Value
MyEnum.get("A");