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.
Related
I need get name from Enum with reflection of java.
I know I can that for class: (but I could not find it about Enums)
public class EnumWrapper<T> {
#SuppressWarnings("unchecked")
public String getType() {
Type type = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) type;
Class<T> entity = (Class<T>) pt.getActualTypeArguments()[0];
String name = entity.getName();
return name;
}
}
I maybe set any of the Enums :
public enum Gender {
WOMAN, MAN, OTHER
}
public enum Language {
Norwegian, ENGLISH, PERSIAN
}
I want to get "Gender" or "Language" only from " getType() " method.
EnumWrapper<Gender> ew = new EnumWrapper<>();
String nameEnum = ew.getType(); // Gender
I'm not sure if this is what you want, but it follows the call style of call you indicated above:
EnumWrapper<Gender> ew = new EnumWrapper<>();
String nameEnum = ew.getType();
This Wrapper class returns the full package name of any parameter type (class or enum). It works using the variable args list, you don't need to supply any values to the constructor it as works off the empty array supplied by the VM:
public class Wrapper<T> {
private String type;
public Wrapper(T...args) {
type = args.getClass().getComponentType().getTypeName();
}
String getType() {
return type;
}
public static void main(String[] args) {
System.out.println(new Wrapper<String>().getType());
System.out.println(new Wrapper<Gender>().getType());
System.out.println(new Wrapper<Language>().getType());
}
}
... prints
java.lang.String
Gender
Language
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();
}
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
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.
Language: Java and Gson
Having parsed a JSON array, how do I:
1) Print all of its contents
2) Iterate over its contents?
For example, here's my code:
String JSInput = "//Json String";
Type listType = new TypeToken<TabClass[]>() {}.getType();
Input_String =GsonObject.fromJson(JSInput, listType);
System.out.println(Input_String.toString());
And the corresponding class description is :
class TabClass{
String Name;
String Parent;
public String getName() {
return Name;
}
public String getParent() {
return Parent;
}
public void setName(String Name) {
this.Name = Name;
}
public void setParent(String Parent) {
this.Parent = Parent;
}
}
The above code only returns a description of the object along with its memory location:
[Lcom.example.projectname.TabClass;#1fbfd6
How do I print the contents of the resultant object, or Iterate over it?
It's not necessary to create a TypeToken just for an array. Gson will deserialize to an array type just fine.
If you have an array, then you don't have to explicitly iterate through its contents just to print. You can use one of the Arrays.toString() methods.
Here's an example.
// output:
// [{value1=one, value2=1}, {value1=two, value2=2}, {value1=three, value2=3}]
import java.util.Arrays;
import com.google.gson.Gson;
public class Foo
{
public static void main(String[] args)
{
Gson GsonObject = new Gson();
String JSInput = "[{\"value1\":\"one\",\"value2\":1},{\"value1\":\"two\",\"value2\":2},{\"value1\":\"three\",\"value2\":3}]";
TabClass[] Input_String = GsonObject.fromJson(JSInput, TabClass[].class);
System.out.println(Arrays.toString(Input_String));
}
}
class TabClass
{
private String value1;
private int value2;
#Override
public String toString()
{
return String.format(
"{value1=%s, value2=%d}",
value1, value2);
}
}
Otherwise, if you'd rather explicitly iterate through the components of the array, with Java you have a few choices for how to do so. A simple one is to use the for-each loop construct.
for (TabClass tab : Input_String)
{
System.out.println(tab);
}
(By the way, "Input_String" is not a good name for this array of TabClass. A more descriptive name might be "tabs".)