Creating model for select component with multidimensional enum in Tapestry - java

In my page class:
public SelectModel getCountryListEnum() {
return new EnumSelectModel(CountryListEnum.class, resources.getMessages());
}
public CountryListEnumEncoder getCountryListEnumEncoder(){
return new CountryListEnumEncoder();
}
In my template (select.selectcountries extends Tapestry Select Component btw):
<t:select.selectcountries id="country" t:id="country" model="CountryListEnum" value="user.address.countrycode" encoder="CountryListEnumEncoder"/>
my enum:
public enum CountryListEnum {
AFGHANISTAN("Afghanistan", "AF"),
ALBANIA("Albania", "AL"),
ALGERIA("Algeria", "DZ"),
(...ETC);
private String country;
private String code;
private CountryListEnum( String country, String code) {
this.country = country;
this.code = code;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getId() {
return getCode();
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
private CountryListEnum() {
}
public static int getSize() {
return values().length;
}
public static String getNameFromCode(String code) {
for (CountryListEnum countryEnum : values()) {
if (code.trim().equals(countryEnum.getCode())) {
return countryEnum.getCountry();
}
}
throw new IllegalArgumentException("Country Code: "+ code + " does not exist");
}
}
My ValueEncoder:
public class CountryListEnumEncoder implements ValueEncoder<CountryListEnum>, ValueEncoderFactory<CountryListEnum> {
#Override
public String toClient(CountryListEnum value) {
return value.getId();
}
#Override
public CountryListEnum toValue(String clientValue) {
Validate.notEmpty(clientValue);
for (CountryListEnum countryEnum : CountryListEnum.values()) {
if (clientValue.trim().equals(countryEnum.getCode())) {
return countryEnum;
}
}
throw new IllegalArgumentException("Country Code: " + clientValue + " does not exist");
}
#Override
public ValueEncoder<CountryListEnum> create(Class<CountryListEnum> type) {
return this; //To change body of implemented methods use File | Settings | File Templates.
}
}
Finaly, I am getting the following error:
java.lang.String cannot be cast to
com.starpoint.instihire.api.domain.reference.CountryListEnum
I tried committing a type coercer (as suggested here) but that didn't work either. I also tried omitting the model param from the select and changing the id of the select.selectcountries component to a countryListEnum (as suggested here). Scratching my head on this one...

Looks like user.address.countrycode is a String and not a CountryListEnum

Related

How do I leverage a json mapping file to convert from one pojo to another pojo?

I have two POJOs (Person.java and User.java) that contain similar information. See below:
public class Person {
private String first_name;
private String last_name;
private Integer age;
private Integer weight;
private Integer height;
public String getFirst_name() {
return first_name;
}
public void setFirst_name(String first_name) {
this.first_name = first_name;
}
public String getLast_name() {
return last_name;
}
public void setLast_name(String last_name) {
this.last_name = last_name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getWeight() {
return weight;
}
public void setWeight(Integer weight) {
this.weight = weight;
}
public Integer getHeight() {
return height;
}
public void setHeight(Integer height) {
this.height = height;
}
}
public class User {
private String name_first;
private String name_last;
private Integer my_age;
private Integer my_weight;
private String social_security;
public String getName_first() {
return name_first;
}
public void setName_first(String name_first) {
this.name_first = name_first;
}
public String getName_last() {
return name_last;
}
public void setName_last(String name_last) {
this.name_last = name_last;
}
public Integer getMy_age() {
return my_age;
}
public void setMy_age(Integer my_age) {
this.my_age = my_age;
}
public Integer getMy_weight() {
return my_weight;
}
public void setMy_weight(Integer my_weight) {
this.my_weight = my_weight;
}
public String getSocial_security() {
return social_security;
}
public void setSocial_security(String social_security) {
this.social_security = social_security;
}
}
I have defined a mapping.json file as shown below using GSON.
{
"columnMap": [
{
"userColumn": "name_first",
"personColumn": "first_name"
},
{
"userColumn": "last_first",
"personColumn": "first_last"
},
{
"userColumn": "my_age",
"personColumn": "age"
},
{
"userColumn": "my_weight",
"personColumn": "weight"
}
]
}
public class Mapping {
private ArrayList<Pair> columnMap;
public Mapping(){
columnMap = new ArrayList<>();
}
public ArrayList<Pair> getColumnMap() {
return columnMap;
}
public void setColumnMap(ArrayList<Pair> columnMap) {
this.columnMap = columnMap;
}
}
I am writing a utility class helper function that converts between a Person and User object the mapped pairs.
public class Pair {
private String userColumn;
private String personColumn;
public String getUserColumn() {
return userColumn;
}
public void setUserColumn(String userColumn) {
this.userColumn = userColumn;
}
public String getPersonColumn() {
return personColumn;
}
public void setPersonColumn(String personColumn) {
this.personColumn = personColumn;
}
public static void main(String args[]){
}
}
My question is below:
As you can see the returnVal object is being set by me (the programmer) to convert from a User POJO to a Person POJO. How do I leverage the pre-defined mapping.json to do this? The reason I am asking is in the future, the mapping.json file may change (maybe the weight mapping no longer exists). So I am trying to avoid re-programming this Utility.userToPerson() function. How can I achieve this? I am thinking Java reflection is the way to go, but I would like to hear back from the Java community.
public class Utility {
public static Person userToPerson(User u){
Person returnVal = new Person();
returnVal.setAge(u.getMy_age()); // <-- Question How do I leverage mapping.json here?
returnVal.setFirst_name(u.getName_first());
returnVal.setLast_name(u.getName_last());
returnVal.setWeight(u.getMy_weight());
return returnVal;
}
}
You can introspect the beans (i.e. User and Person) for the field names and call corresponding getter from User to fetch the value. Later call corresponding setter in Person.
Here I have taken userToPersonFieldsMap for mapping the field, you can load mapping from JSON file and construct the map accordingly.
Important code section is the for loop, where it dynamically calls getter and setter and does the job.
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
public class UserToPersonMapper {
public static void main(String[] args) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
Map<String, String> userToPersonFieldsMap = new HashMap<>();
userToPersonFieldsMap.put("name_first", "first_name");
userToPersonFieldsMap.put("last_first", "first_last");
userToPersonFieldsMap.put("age", "personAge");
//existing user
User user = new User("Tony", "Stark", 20);
//new person - to be initialised with values from user
Person person = new Person();
for (Map.Entry<String, String> entry : userToPersonFieldsMap.entrySet()) {
Object userVal = new PropertyDescriptor(entry.getKey(), User.class).getReadMethod().invoke(user);
new PropertyDescriptor(entry.getValue(), Person.class).getWriteMethod().invoke(person, userVal);
}
System.out.println(user);
System.out.println(person);
}
}
class User {
private String name_first;
private String last_first;
private int age;
public User(String name_first, String last_first, int age) {
this.name_first = name_first;
this.last_first = last_first;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName_first() {
return name_first;
}
public String getLast_first() {
return last_first;
}
public void setName_first(String name_first) {
this.name_first = name_first;
}
public void setLast_first(String last_first) {
this.last_first = last_first;
}
#Override
public String toString() {
return "User{" +
"name_first='" + name_first + '\'' +
", last_first='" + last_first + '\'' +
", age=" + age +
'}';
}
}
class Person {
private String first_name;
private String first_last;
private int personAge;
public void setFirst_name(String first_name) {
this.first_name = first_name;
}
public void setFirst_last(String first_last) {
this.first_last = first_last;
}
public String getFirst_name() {
return first_name;
}
public String getFirst_last() {
return first_last;
}
public int getPersonAge() {
return personAge;
}
public void setPersonAge(int personAge) {
this.personAge = personAge;
}
#Override
public String toString() {
return "Person{" +
"first_name='" + first_name + '\'' +
", first_last='" + first_last + '\'' +
", personAge=" + personAge +
'}';
}
}
You can tweak and try it out this example to make it more align with your requirement.
Note:
This solution uses reflection.

Can we have space within a constant in Enum in Java

I need something like this
public enum SolutionType {
RMS,
CPA,
BUSINESS DRIVERS,
NA
}
where BUSINESS DRIVERS is a value with space
Java forbids the use of spaces in enums.
However you could use an underscore and implement a custom toString():
public enum SolutionType {
RMS, CPA, BUSINESS_DRIVERS, NA;
#Override
public String toString() {
return this.name().replace("_", " ");
}
}
Or just add a custom field to the enum:
public enum SolutionType {
RMS, CPA, BUSINESS_DRIVERS("BUSINESS DRIVERS"), NA;
private String readableName;
private SolutionType() {
this.readableName = this.name();
}
private SolutionType(String name) {
this.readableName = name;
}
public String getReadableName() {
return this.readableName;
}
}
or a mix of the two...
public enum SolutionType {
RMS, CPA, BUSINESS_DRIVERS("BUSINESS DRIVERS"), NA;
private String readableName;
private SolutionType() {
this.readableName = this.name();
}
private SolutionType(String name) {
this.readableName = name;
}
#Override
public String toString() {
return this.readableName;
}
}

Assign one json value for two fields in java using GSON

I am trying to assign the value returned by some function to a field in the deserialized class of json.
FileInfo.java
public class FileInfo {
#SerializedName("Name")
private String mName;
#SerializedName("Url")
private String mUri;
#SerializedName("Size")
private Integer mSize;
#SerializedName("ModTime")
private Long mModifiedTime;
private FileType mType;
#SerializedName("Children")
private ArrayList<FileInfo> mChildren = new ArrayList<>();
public ArrayList<FileInfo> getChildren() {
return mChildren;
}
public long getModifiedTime() {
return mModifiedTime;
}
public String getName() {
return mName;
}
public Integer getSize() {
return mSize;
}
public String getUrl() {
return mUri;
}
public FileType getType() {
return mType;
}
public void setChildren(ArrayList<FileInfo> mChildren) {
this.mChildren = mChildren;
}
public void setModifiedTime(long mModifiedTime) {
this.mModifiedTime = mModifiedTime;
}
public void setName(String mName) {
this.mName = mName;
}
public void setSize(Integer mSize) {
this.mSize = mSize;
}
public void setType(FileType mType) {
this.mType = mType;
}
public void setUri(String mUri) {
this.mUri = mUri;
}
#Override
public String toString() {
return FileInfo.class.toString();
}
public FileInfo() {
}
}
The mType needs to be assigned to foo(mName). I looked up custom deserializers and instance creators but none of those helped. I also thought of TypeAdapters which i feel defeats the purpose of keeping deserialization(using GSON) simple.
This is a sample JSON string that will be deserialized.
[
{
"Name":"Airport",
"Url":"http://192.168.2.2/api/sites/Baltimore%20Airport/Airport",
"Size":0,
"ModTime":"2015-12-02T14:19:17.29824-05:00",
"Children":null
}
]
P.S. I'm not sure if this should be done during deserialization but trying anyways. Also please let me know of alternative ways to achieve this.

Jersey Jackson Serializing Parent Fields

I have an object "A" which extends object "B" when object "A" gets serialized the fields from object "B" do not get serialized into JSON. Any Ideas? Here are my objects involved.
public class CreateNewPlayerAndLoginResponse extends EPNetResponse{
private PlayerSession playerSession;
public CreateNewPlayerAndLoginResponse() {
}
public CreateNewPlayerAndLoginResponse(Integer playerId, String playerSessionId) {
this.playerSession = new PlayerSession(playerId, playerSessionId);
}
public CreateNewPlayerAndLoginResponse(EPNetErrorEnum error) {
super(error);
}
public CreateNewPlayerAndLoginResponse(EPNetError error) {
super(error);
}
public PlayerSession getPlayerSession() {
return playerSession;
}
public void setPlayerSession(PlayerSession playerSession) {
this.playerSession = playerSession;
}
#Override
public String toString() {
return "CreateNewPlayerAndLoginResponse{" + "playerSession=" + playerSession + '}';
}
}
public class EPNetResponse implements Serializable{
private EPNetError error;
public EPNetResponse() {
}
public EPNetResponse(EPNetError error) {
this.error = error;
}
public EPNetResponse(EPNetErrorEnum error){
this.error = new EPNetError(error);
}
public EPNetError getError() {
return error;
}
public void setError(EPNetError error) {
this.error = error;
}
#JsonIgnore
public boolean isError(){
if(error == null){
return false;
}
return true;
}
}
public class EPNetError implements Serializable{
private static final int UNEXPECTED_ERROR = 5417;
private Integer code;
private String message;
public EPNetError() {
}
public EPNetError(EPNetErrorEnum error){
this.code = error.getCode();
this.message = error.getMessage();
}
public EPNetError(EPNetErrorEnum error, String message){
this.code = error.getCode();
this.message = message;
}
public EPNetError(String message){
this.code = EPNetError.UNEXPECTED_ERROR;
this.message = message;
}
public EPNetError(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
All I get as the serialized response is
{"playerSession":null}
Even though I am 100% sure there is an error message part of the object before serialization.
Also worth mentioning I am using Jackson 1.9.2 and Jersey 1.13
If you are expecting 'error' to be included, problem is that #JsonIgnore in isError(), without any other annotations. So, add #JsonProperty next to getError() and it should be included. You may also need to add it to setError().
The problem here is that Jackson consider #JsonIgnore here to mean "ignore property 'error'", whereas you are probably only hoping to ignore that particular accessor.

Java getting the Enum name given the Enum Value

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

Categories