Java Enum to String Map maintaining consistency - java

I am new to Java and working on writing a Enum to String Map for headers.
public class Header {
// When adding HeaderType make sure it is consistent with the header name map
public enum HeaderType {
MARKER,
WIDTH,
......
};
private String name;
private String value;
private HeaderType headerType;
// Create an immutable map for header enum to header names
private static final Map<HeaderType, String> headerNameMap;
static {
Map<HeaderType, String> headerNameMapTemp = new HashMap<HeaderType, String>();
headerNameMapTemp.put(HeaderType.MARKER, "MA");
headerNameMapTemp.put(HeaderType.WIDTH, "WI");
headerNameMap = Collections.unmodifiableMap(headerNameMapTemp);
}
public Header(HeaderType headerType, String value) {
this.headerType = headerType;
this.name = Header.getHeaderName(this.headerType);
this.value = value;
}
private static String getHeaderName(HeaderType headerType) {
return headerName.get(headerType);
}
In the above code I use HeaderType enum and use an immutable HashMap to convert from enum to header name. As you can see adding another header type involves adding it in the map as well. So the user of this should make sure it's added in two places to avoid any mess later. Are their any clean alternatives for this functionality?

You can make the header name a field in the enum itself, like this:
public enum HeaderType {
MARKER("MA"),
WIDTH("WI");
// FOO(), BAR; Won't compile
private final String name;
private HeaderType(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
This way it will not be possible to add a new HeaderType without specifying a corresponding name as well and your getHeaderName method could simply be replaced with a call to getName().
You can enumerate all type/name combinations using the enum's values() method:
for (HeaderType headerType : HeaderType.values()) {
System.out.println(headerType.getName());
}
Running sample: https://ideone.com/B5LwQz

Related

What approach better for POJO (fields formatting logic)?

I'm working with JSON. So I have following POJO classes Position, Person.
Where Person my needed class.
I need to receive formatted values of fields only of Person (I'm using only this class, Position it's class accroding my JSON strucutre)
Where better implement formatting logic in Position or Person?
1st variant, formatting logic in Position class
public Position {
private String value;
public String getFormattedValue() {
//Value formatting...
return value;
}
public Person {
private Position position;
..other fields
public String getFormattedValue() {
return position.getFormattedValue();
}
}
//using
String neededFormattedValue = new Person().getFormattedValue();
2nd variant, formatting logic in Person class
public Position {
private String value;
public String getValue() {
return value;
}
public Person {
private Position position;
..other fields
public String getFormattedValue() {
String value = position.getValue()
//Value formatting...
return value;
}
}
//using
String neededFormattedValue = new Person().getFormattedValue();
I would suggest to have second variant, as you Position class should not have formatting logic.
The second one is more loosely coupled.
I have been having problems converting between JSON, POJO and XML.
So it seems best to use the exact name for get / set, albeit the first character - which is always capitalized.
Eg. If the fields use correct formatting, Android Studio usually suggests the methods(functions) names. Where the class contains private String value;, when you begin typing public get... AS should provide you a list. The correct syntax for the get method would be public getValue() ....
public class abc()
{
private String value;
private int some_id_of_a_record;
private String anotherString;
public String getValue()
{...}
public int getSome_id_of_a_record()
{...}
public String getAnotherString()
{...}
...
}

Object to string delimited format

I have set of objects of different types.
Ex : Employee emp, adress adr
These two classes have list of properties
public class Employee{
private Stringname;
private int age;
}
public class Adress {
private String HouseNo;
private string Street;
private string pin;
}
Each attribute is assigned with some 2 character value
Name (NA), age (AG), HouseNo(HN),Street(ST), pin(PN)
I need to construct a string with these data and delimit with a %
Output:
NA%Vidhya%AG%30%HN%80%ST%1st cross%PN%100100
Each class knows it own data best so I would let each class be responsible for generating the string. As I understand it the two char codes for each field are unique for each class and member and only used when generating the string so only the class would need them.
interface AttributeDescription {
String generateDescription();
}
public class Employee implements AttributeDescription {
//members...
public String generateDescription() {
return String.format(“NA%%%s%%AG%%%d”, name, age)
}
Then simply call this method for all objects implementing the interface.
AttributeDescription object = ...
String attr = object.generateDescription();
I don't think it can be generalized more than this given the requirements.
Update
It might be better to have a builder class for building the string to get a more unified behavior between classes. Here is an example
public class AttributeBuilder {
private builder = new StringBuilder();
public String getAttribute() {
return builder.toString();
}
public void add(String code, String value) {
if (value == null) {
return;
}
builder.append(code);
builder.append(‘%’);
builder.append(value);
builder.append(‘%’);
}
}
And then you would also have to implement add(...) methods for other data types in a similar fashion. The builder could then be used like
public String generateDescription() {
AttributeBuilder builder = new AttributeBuilder();
builder.add(“NA”, name);
builder.add(“AG”, age);
return builder.getAttribute();
}

Serialize/deserialize immutable objects that carry extra informations with Jackson

I try to use only immutables objects in my application. I've got a REST service that will take arbitrary JSon objects as input.
I've a Java class that map theses objects, and I want to make them immutable + able to deal with extra parameters (just like using #JsonAnySetter).
Here is my java class:
public class Operation {
private final String _id;
private final String state;
private final Map<String, Object> extra;
public Operation(String _id, String state, Map<String,Object> extra) {
this._id = _id;
this.state = state;
this.extra = extra;
}
// getters....
}
Using #JsonAnySetter I would have:
public class Operation {
private final String _id;
private final String state;
private Map<String, Object> extra = new HashMap<>();
public Operation(String _id, String state) {
this._id = _id;
this.state = state;
}
#JsonAnySetter
public void addExtra(String key, Object value) {
this.extra.put(key,value);
}
// getters....
}
But this is not immutable anymore !
This will not work because Jackson do not find any "extra" json attribute to read. I would like that everything that cannot be mapped be added to my map.
Any idea of how to do this ? (or is it just possible :)
Note: I use javac with -parameters option and the ParameterNameModule from jackson so that I don't need #JsonCreator option.
Ok so I respond to myself :)
It seems that it is not possible to do that using only Jackson.
Because I want immutability, I've turned myself to the 'immutables' framework: http://immutables.github.io/
With a little configuration, it will deal with extra parameters as stated in the following report: https://github.com/immutables/immutables/issues/185.
In my situation, I've got the following code:
#Value.Immutable
#JsonSerialize(as = ImmutableOperation.class)
#JsonDeserialize(as = ImmutableOperation.class)
public abstract class Operation {
#JsonAnyGetter
#Value.Parameter
public abstract Map<String, String> extra();
}
Refer to the documentation of immutables for the details.
If you want to deserialize immutable entity with extra arguments you can utilize builder pattern:
#JsonPOJOBuilder
public class OperationBuilder {
private String _id;
private String _state;
private Map<String, Object> extra = new HashMap<>();
#JsonAnySetter
public OperationBuilder addExtra(String key, Object value) {
this.extra.put(key,value);
return this;
}
// setters....
public Operation build() {
return new Operation(...arguments...)
}
And your original class should have this annotation on a class level:
#JsonDeserializer(builder = OperationBuilder.class)
This way all your known and unknown (extra) fields will be populated inside the builder and then Jackson will call build() method at the end of the deserialization.

Are there any advantages between List<CustomObject> and HashMap <String, Object>

I am trying to implement a solution (in Java 1.6) where i need to store some values (for a set of properties) and thinking in three options considering the following three (Any other idea is of course wellcome!)
Option 1
Create a class (call it Property) that can store different type of objects (String, int, boolean...) and and work with the set of properties as a List<Property>
Something like:
private String type; //Store the type of Object
private String name; //Store the name of the property
private String valueStr; //Store the String value
private int valueInt; //Store the int value
private boolean valueBool; //Store the boolean value
I dont really like the idea of having many properties and using only one of them. (only one of the values will be set per property)
Option 2
Use HashMap<String, Object> and parse the type on each case.
Have the good thing that you can get the Property by name
Option 3
Use HashMap<String, Property> Where the String is the name of the property and you can get the value with the name and no need to parse.
Questions are:
Which of one you think is the best one?
or if none of them are good i would like to hear other ideas
Also is there any performance difference between the List and the HashMap?
Thanks in advance for the help.
I think better is to have a custom Value class like this:
public class MyValue {
enum Type {
INT, STRING, BOOL;
}
private Type type; //Store the type of Object in Type Enum
private Object value; //Store the value in Object
public void setValue(int val) {
type = Type.INT;
value = new Integer(val);
}
public void setValue(String val) {
type = Type.STRING;
value = val;
}
public void setValue(boolean val) {
type = Type.BOOL;
value = new Boolean(val);
}
public String stringVal() {
// check type to be STRING first
return (String) value;
}
public int intVal() {
// check type to be INT first
return ((Integer) value.intValue());
}
public boolean booleanVal() {
// check type to be BOOL first
return ((Boolean) value.booleanValue());
}
}
You will need to convert from Object to specific type based on enum Type in your getters.
Another option would be something like this, using inheritance rather than keeping a large number of unused fields around.
public interface Property {
String getType();
String getName();
Object getValue();
}
public abstract class AbstractProperty implements Property {
private final String name;
protected AbstractProperty(String name) {
this.name = name;
}
}
public class StringProperty extends AbstractProperty {
private final String value;
public StringProperty(String name, String value) {
super(name);
this.value = value;
}
#Override
public String getType() {
return String.class.getName();
}
#Override
public String getValue() {
return value;
}
}
public class IntegerProperty extends AbstractProperty {
private final Integer value;
public IntegerProperty(String name, Integer value) {
super(name);
this.value = value;
}
#Override
public String getType() {
return Integer.TYPE.getName();
}
#Override
public Integer getValue() {
return value;
}
}
I think option 2 would be the best for you. Considering that you are storing properties I am expecting that you would be querying this list quite often which again points in the direction of a HashMap as that would make your lookup very efficient.
I suggest using an enum instead. Enums are good for holding lists of values, and are effective at retrieval.
public enum Property {
TYPE,
NAME,
VALUEINT; //...
private String sProp = "";
private int iProp = 0;
private boolean bProp = false;
public String getStringProp() {return sProp;}
public int getIntProp() {return iProp;}
public boolean getBoolProp() {return bProp;}
public void setStringProp(String str) {this.sProp = str;}
public void setIntProp(int i) {this.iProp = i;}
public void setBoolProp(boolean b) {this.bProp = b;}
}
This can then be accessed with Property.TYPE, Property.VALUEINT, etc. You can set properties with Property.TYPE.setStringProp(), and get them with Property.TYPE.getStringProp().
You can read more about enums from Oracle's site.
I am unsure if there's one 'best' way. It really depends on how the data would be used after storing in a data structure.
In cases when I just need to accumulate properties and do something on each of them, I'd use a list, or even an array, sometimes.
If you might have to get a particular property, say by name, then a HashMap could help.
Again if you want to use the native object type or an instance of Property depends on what kind of data you have.
Which performs better depends on the number of objects you have, how you'd access them for use, how often you'd insert and several other factors.

Casting objects via reflection in Java

I am writing a deserializer method, which looks like so:
public <T> T deserialize(Object[] result, String[] fields, Class<T> type);
So basically I will be passed in a result array of data which is all objects, and a class type T which I need to convert the data in the array to the types in the given class, and create a new class of type T and return it. The String[] fields is the field names corresponding to the data in Object[] result. The field names will correspond to the Class T.
The casting will need to use reflection of the given class to find out the type of each field.
eg.
result = ["Mike", "London", 28];
fields = ["name", "location", "age" ];
Class T =
public class GivenClass{
private String name;
private String location;
private Integer age;
public GivenClass(String name, String location, Integer age){
this.name = name;
this.location = location;
this.age = age;
}
}
Class implementation
static class GivenClass {
private String name;
private String location;
private Integer age;
public GivenClass(String name, String location, Integer age) {
this.name = name;
this.location = location;
this.age = age;
}
public GivenClass(Map<String, Object> data) throws Exception {
for (Field f : GivenClass.class.getDeclaredFields())
f.set(this, data.get(f.getName()));
}
public Map<String, Object> serialize() throws Exception {
Map<String, Object> fields = new HashMap<String, Object>();
for (Field f : GivenClass.class.getDeclaredFields())
fields.put(f.getName(), f.get(this));
return fields;
}
#Override
public String toString() {
return "age=" + age + ", location=" + location + ", name=" + name;
}
}
Example:
public static void main(String[] args) throws Exception {
GivenClass o1 = new GivenClass("Mike", "London", 28);
Map<String, Object> serialized = o1.serialize();
GivenClass o2 = new GivenClass(serialized);
System.out.println(o2.toString());
}
Output:
age=28, location=London, name=Mike
You need to do the conversion yourself. Reflections doesn't convert (it will only check the type of an object is already correct)
Reflections won't give you the names of method/constructor parameters. (You can get them from the debug byte code but that's a real pain)
The approach I take is to use the convention that the constructor parameters are in the same order as the fields. You will also want to assume the type of constructor parameters and field types match. ;)
I would also use primitives instead of wrappers whenever possible. Use int unless you want null to be a valid option. If this is the case you should think about how you want to represent this. For text I usually use empty strings or blank field for null or NaN depending on the context.
The problem with this, is that in Java it's unable to fetch the parameter names of a constructor.
For this particular example, you'll need a default constructor, with which you could create an empty object.
public GivenClass() {
super();
}
Then you could use reflection to get the fields of the class, and then set the appropriate value for them.
But I think it would be much easier to annotate your constructor, and then fetch the annotation informations in your deserialize method. In this case you won't need to fetch the fields and create an empty constructor.
Example:
You need to create a annotation like this:
#Target({ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
public #interface Property
{
String value();
}
And then you can use it in your constructor like this:
public GivenClass(#Property("name") String name, #Property("location") String location, #Property("age") Integer age) {
// ...
}
As Peter Lawrey says, casting does not convert a string into an integer.
If your bean follows the standard bean conventions (ie you have getters & setters), then you can use BeanUtils. BeanUtils does some standard conversions, and you can add more by adding a Convertor.
See the following example:
import org.apache.commons.beanutils.BeanUtils;
public class BeanUtilsTest {
public static class Obj {
private int number;
private String string;
public void setNumber(int number) {
this.number = number;
}
public void setString(String string) {
this.string = string;
}
public String toString() {
return "number=" + number + " string=" + string;
}
}
public static void main(String args[]) throws Exception {
String[] values = new String[] { "1", "two" };
String[] properties = new String[] { "number", "string" };
Obj obj = new Obj();
for (int i = 0; i < properties.length; i++) {
BeanUtils.setProperty(obj, properties[i], values[i]);
}
System.out.println("obj=" + obj);
}
}
This produces as output:
obj=number=1 string=two
Note that the above example has only setters, but still works.

Categories