Construct a class from HashMap - java

I want to write a constructor to set values from a HashMap. Can you please advise what is the best way to do this?
Write now I am using switch statement to call methods based on HashMap key, but I am wondering whether there is any better alternative.
FYI, in the myItems class, I actually have 25 variables to set.
public class MainClass{
BufferedReader br = new BufferedReader(new FileReader(file));
String[] datakey = br.readLine().split(";"); // getting header, 25 of them
HashMap<String,String> bookmap = new HashMap<String,String>();
String[] dataarr = line.split(";"); // getting values, 25 of them
int k = 0;
for(String d : datakey){
bookmap.put(d, dataarr[k++]); // Key-Value Pair
}
myItems item = new myItems(bookmap); // HOW TO WRITE THIS CONSTRUCTOR?
}
public class myItems {
String _id="";
String _name="";
String _genre="";
String _language="";
int _rating=0;
int _price=0;
...........................
...//25 OF THEM...
...........................
public myItems(HashMap<String,String> allrec){
Iterator<Map.Entry<String,String>> it = allrec.entrySet().iterator();
while(it.hasNext()){
Map.Entry pairs = (Map.Entry)it.next();
Switch(pairs.getKey()){
case "id":
setid(pairs.getValue());
break;
case "name":
setname(pairs.getValue());
break;
Deafult:
break;
}
}
}
public int getid(){
return this._id;
}
public String getname(){
return this._name;
}
..............................
..............................
..............................
public void setid(int id){
this._id = id;
}
public void setname(String name){
this._name = name;
}
..............................
..............................
..............................
}

Why don't you just write it strait forward like this:
public myItems(HashMap<String,String> allrec){
setid(allrec.get("id");
setname(allrec.get("name");
}
If you don't want any attribute to be assigned a null value then you should check if the Map returns a null:
public myItems(HashMap<String,String> allrec){
String id = allrec.get(id);
if(id != null)
setid(id);
// ...
}
There is actually another solution for your problem. Why bother storing those value in attributes anyway? You can just store them in the Map itself. Your constructor will be something like this:
private Map<String, String> mAttributes;
public myItems(HashMap<String, String> allrec) {
mAttributes = allrec;
}
Note that you should consider making a copy of the whole map instead of storing reference like above. Then write set methods like this:
public void setId(String id) {
mAttributes.put("id", id);
}
And your get methods are like this:
public String getId() {
return mAttributes.get("id");
}

You can use Reflection for that. Imagine that some fields have setters (okay for datastructures, questionable for classes - and what about mutability vs. immutability?), others haven't. Then you could do it like this:
import java.lang.reflect.Method;
public void setAll(final Map<String, String> fieldMap) {
for (final Map.Entry<String, String> entry : fieldMap.entrySet())
setField(entry);
}
public void setField(final Map.Entry<String, String> entry) {
setField(entry.getKey(), entry.getValue());
}
public void setField(final String name, final String value) {
final Method fieldSetter = getFieldSetter(name);
if (fieldSetter != null) {
fieldSetter.invoke(this, value);
return;
}
final Field field = getField(name);
if (field != null) {
field.set(this, value);
return;
}
// Throw some exception
}
public Method getFieldSetter(final String fieldName) {
return getMethod(getSetterName(fieldName));
}
public static String getSetterName(final String fieldName) {
return "set" + upperCaseFirst(fieldName);
}
public static String upperCaseFirst(final String s) {
return Character.toUpperCase(s.charAt(0)) + s.substring(1);
}
public Method getMethod(final String methodName) {
final Class<?> clazz = getClass();
try {
return clazz.getMethod(methodName, String.class);
} catch (final NoSuchMethodException ignore) { }
try {
return clazz.getDeclaredMethod(methodName, String.class);
} catch (final NoSuchMethodException ignore) { }
return null;
}
public Field getField(final String fieldName) {
final Class<?> clazz = getClass();
try {
return clazz.getField(fieldName);
} catch (final NoSuchFieldException ignore) { }
try {
return clazz.getDeclaredField(fieldName);
} catch (final NoSuchFieldException ignore) { }
return null;
}
There are some exceptions to be handled, you will need to change the source code accordingly.
AFAIR on Android Reflection comes at a performance penalty. You might want to keep an eye on that method's performance.

Related

Sort Linked List based on dynamic field from user

My objective is to Dynamically insert values in to the Linked List. And thereafter, I want to perform sorting or search algorithms on the List.
In addition to it, I am creating class at runtime (based on user input) using Reflection.
Thereafter, I use data provided by the user in JSON Array, to create instances of the class, and then I insert the instances in to the GenericList.
Following is the code for the Generic Linked List.
public class LinkedListNode<T> implements Serializable {
private T value;
private LinkedListNode<T> next;
public LinkedListNode(T value) {
this.value = value;
}
public void setNext(LinkedListNode<T> next) {
this.next = next;
}
public LinkedListNode<T> getNext() {
return next;
}
public T getValue() {
return value;
}
}
public class GenericList<T> implements Serializable {
private LinkedListNode<T> first = null;
public void insert(LinkedListNode<T> node) {
node.setNext(first);
first = node;
}
public void emptyList(){
first = null;
}
public void remove(){
if(first.getNext()!=null)
first = first.getNext();
else first = null;
}
}
And this is how I create instances of the class and insert it to the GenericList.
//dataToInsert => is the JSONArray. => [{field1:"value1",field2:"value1"},{field1:"value2",field2:"value2"},{field1:"value3",field2:"value3"}]
//classLoaded => package com.LinkedAnalyzerAdapter.saveTestClasses; public class order implements java.io.Serializable {public String field1;public String field2;}
Class<?> classLoaded = classLoader.loadClass("com.LinkedAnalyzerAdapter.saveTestClasses.order");
GenericList<Object> list = new GenericList<Object>();
for (int i = 0; i < dataToInsert.length(); i++) {
JSONObject jsonObj = new JSONObject();
jsonObj = dataToInsert.getJSONObject(i);
Object obj = classLoaded.newInstance();
Field[] fs = classLoaded.getDeclaredFields();
for (Field field : fs)
{
field.setAccessible(true);
Object fieldValue = jsonObj.get(field.getName());
field.set(obj, fieldValue);
}
list.insert(new LinkedListNode<Object>(obj));
}
I am successfully able to insert data in to GenericList, but after inserting I later want to sort the data based on field1, in the ascending order.
I have spent hours to solve it but unable to successfully accomplish sorting.
You should really use java.util.LinkedList instead of your own GenericList, to take advantage of the built in Collections
LinkedList<LinkedListNode<?>> list = new LinkedList<>();
Collections.sort(list, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return ...
}
}
Used the following code to resolve the issue.
public void sortLinkedList(final String fieldToCompare){
Collections.sort(testList, new Comparator<LinkedListNode>() {
#Override
public int compare(LinkedListNode arg0, LinkedListNode arg1) {
// TODO Auto-generated method stub
Field[] fs = classtoLoad.getDeclaredFields();
for (Field field : fs){
field.setAccessible(true);
Object fieldName = field.getName();
if(fieldToCompare.equalsIgnoreCase((String) fieldName)){
try {
String value1 = (String) field.get(arg0.getValue());
String value2 = (String) field.get(arg1.getValue());
return value1.compareToIgnoreCase(value2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
}
return 0;
}
});
}

CacheLoader loading the same keys in multiple times

I am getting duplicate keys in my cacheIterator.
I'm calling a web service using SOAP to rate policies for an insurance company. I am attempting to use a Cachebuilder / loader to store the DTO's as a key and the response from the service as a value. From what I've researched, the .get and .getUnchecked methods will get a value from the cache and if it's not there, it will load that value into the cache.
here is some code:
public class CacheLoaderImpl
{
private static CacheLoaderImpl instance = null;
private static LoadingCache<PolicyDTO, RatingServiceObjectsResponse> responses;
protected CacheLoaderImpl()
{
responses = CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(
new CacheLoader<PolicyDTO, RatingServiceObjectsResponse>() {
public RatingServiceObjectsResponse load(PolicyDTO key)
throws Exception
{
return getResponse(key);
}
});
}
public static CacheLoaderImpl getIntance()
{
if(instance == null)
{
instance = new CacheLoaderImpl();
}
return instance;
}
public LoadingCache<PolicyDTO, RatingServiceObjectsResponse> getResponses()
{
return responses;
}
public RatingServiceObjectsResponse getResponse(PolicyDTO key) throws ExecutionException
{
RatingServiceObjectsResponse response = new RatingServiceObjectsResponse();
try
{
response = new CGIRatabaseServiceImpl().getCoverages(key);
}
catch (RemoteException e)
{
e.printStackTrace();
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
return response;
}
}
And this is where I call the get method:
RatingServiceObjectsResponse response = CacheLoaderImpl.getIntance().getResponses().get(policy.toCoveragesCallDTO());
I was under the assumption that maybe it was comparing memory addresses which would be different so I overwrote the toString method to convert the DTO object to JSON. Upon inspecting the cache I can see that the keys are exactly the same with a compare tool. Yet, they're still being stored and calling the service every single time. I tried overwriting the equals method on PolicyDTO but it is never hit when I debug.
How can I make the cacheloader only load values of different keys and pull existing values out as it is originally intended?
I think I just don't have a solid idea how the cacheLoader actually works. I appreciate any help or suggestions.
PolicyDTO class:
public class PolicyDTO extends AbstractDto implements IPolicyDTO
{
private ArrayList<ILineOfBusinessDTO> lobDTOs = new ArrayList<ILineOfBusinessDTO>();
private String pcInd;
private String ratingEffectiveDate;
private String companyName;
public String getPcInd()
{
return pcInd;
}
public void setPcInd(String pcInd)
{
this.pcInd = pcInd;
}
public String getRatingEffectiveDate()
{
return ratingEffectiveDate;
}
public void setRatingEffectiveDate(AdvancedDate ratingEffectiveDate)
{
if(ratingEffectiveDate != null)
{
this.ratingEffectiveDate = ratingEffectiveDate.toFormattedStringMMDDYYYY();
}
else
{
this.ratingEffectiveDate = new AdvancedDate().toFormattedStringMMDDYYYY();
}
}
public String getCompanyName()
{
return companyName;
}
public void setCompanyName(String companyName)
{
this.companyName = companyName;
}
public DtoType getType()
{
return hasGetCoveragesCoverageDTO() ? DtoType.GET_COVERAGE_POLICY : DtoType.RATE_POLICY;
}
public boolean hasGetCoveragesCoverageDTO()
{
if(lobDTOs != null)
{
for(ILineOfBusinessDTO lineDTO : lobDTOs)
{
if(lineDTO.hasGetCoveragesCoverageDTO())
{
return true;
}
}
}
return false;
}
#Override
public void addLob(ILineOfBusinessDTO lob) {
lobDTOs.add(lob);
}
#Override
public Iterator<ILineOfBusinessDTO> getLobIterator() {
return lobDTOs.iterator();
}
public ICoverageDTO findCoverage(String coverageID)
{
ICoverageDTO coverageDTO = null;
for(ILineOfBusinessDTO lineDTO : lobDTOs)
{
coverageDTO = lineDTO.findCoverage(coverageID);
if(coverageDTO != null)
{
return coverageDTO;
}
}
return null;
}
#Override
public String toString()
{
return JSONConversionUtility.convertPolicyDTO(this);
}
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result
+ ((companyName == null) ? 0 : companyName.hashCode());
result = prime * result + ((lobDTOs == null) ? 0 : lobDTOs.hashCode());
result = prime * result + ((pcInd == null) ? 0 : pcInd.hashCode());
result = prime
* result
+ ((ratingEffectiveDate == null) ? 0 : ratingEffectiveDate
.hashCode());
return result;
}
#Override
public boolean equals(Object object)
{
if(object instanceof PolicyDTO)
{
return object.toString().equals(this.toString());
}
return false;
}
}
Your PolicyDTO class has hashCode inconsistent with equals - it violates the following rule:
If two objects are equal according to the equals(Object) method, then
calling the hashCode method on each of the two objects must produce
the same integer result.
Cache uses hashCode (much like HashMap class does), so when it sees two keys with different hashcodes, it assumes they are not equal.

Circumvent that storing an #Embedded field holding null is instantiated when loaded?

If a Person without an Address is persisted and loaded later on, Person contains an Address with all fields set to null.
This (modified) example was taken from coderanch, where a similar problem was reported.
#Embeddable
public class Address {
private String street;
private String postalCode;
}
#Entity
public class Person {
private String name;
#Embedded
private Address home;
}
How can I circumvent this problem? Is is possible to instruct Hibernate not to instantiate an #Embedded object, if all fields are null?
Changing the getters for every #Embedded field seems cumbersome and error prone. Another cumbersome alternative would be the use of #PostLoad, but this is called just for #Entitys, not for #Embeddables.
well, I wrote something which helped in my case. I added it with #PostLoad to #Entitys with #Embeddables:
public class NullableEmbeddedCleanerImpl implements NullableEmbeddedCleaner {
private final static Logger LOGGER = LoggerFactory.getLogger(NullableEmbeddedCleaner.class);
Map<Class<?>, Predicate<Object>> classFilterForNullables = new HashMap<>();
Map<Class<?>, Predicate<Object>> collectionMap = new HashMap<>();
Set<Class<?>> primitiveArrayClasses = new HashSet<Class<?>>();
public NullableEmbeddedCleanerImpl() {
fillPredicates();
fillCollectionMap();
fillPrimitiveArrayClasses();
}
/**
* B C D F I J S Z
*/
private void fillPrimitiveArrayClasses() {
try {
primitiveArrayClasses.addAll(Arrays.asList(Class.forName("[B"), Class.forName("[B"), Class.forName("[C"),
Class.forName("[D"), Class.forName("[F"), Class.forName("[I"), Class.forName("[J"), Class.forName("[S"),
Class.forName("[Z")));
} catch (ClassNotFoundException e) {
LOGGER.error("Class not found", e);
}
}
#SuppressWarnings("unchecked")
private void fillCollectionMap() { // misses Lists, Maps, ...
collection(Set.class, s -> {
final Set<Object> toRemove = new HashSet<>();
for (Object i : s) {
try {
if (clean(i)) {
toRemove.add(i);
}
} catch (Exception e) {
LOGGER.warn("Error cleaning embeddable {} : {}", e, i);
}
}
s.removeAll(toRemove);
return s.isEmpty();
});
}
#Override
public final void embeddables(Object... arg) {
for (Object i : arg) {
try {
clean(i);
} catch (IllegalArgumentException | IllegalAccessException e) {
LOGGER.warn("Error cleaning embeddable {} : {}", e, i);
}
}
}
#Override
public final boolean clean(Object arg) throws IllegalArgumentException, IllegalAccessException {
if (arg == null) {
return true;
}
boolean cleanThis = true;
Vector<Field> fields = new Vector<>();
for (Class<?> clazz = arg.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
}
for (Field field : fields) {
if (!fieldLoop(field, arg)) {
cleanThis = false;
}
}
return cleanThis;
}
private boolean fieldLoop(Field field, Object arg) throws IllegalArgumentException, IllegalAccessException {
if (Modifier.isStatic(field.getModifiers())) { // skip static fields
return true;
}
field.setAccessible(true);
Object fieldValue = field.get(arg);
if (fieldValue == null) {
return true;
}
Class<?> fieldsClass = field.getType();
if (fieldsClass.isPrimitive() || fieldsClass.isEnum()) {
return false; // can not clean primitives nor enums
}
if (fieldsClass.isArray()) {
if (primitiveArrayClasses.contains(fieldsClass)) {
return false; // ignore primitive arrays
} else {
throw new UnsupportedOperationException("Do something useful here"); // object
// arrays
}
}
for (Class<?> clazz : collectionMap.keySet()) {
if (clazz.isAssignableFrom(fieldsClass)) {
boolean emptyCollection = collectionMap.get(clazz).test(fieldValue);
if (!emptyCollection) {
return false;
} else {
field.set(arg, null);
}
return true;
}
}
// test primitives. just classes, no interfaces >>
for (Class<?> fieldClass = fieldsClass; fieldClass != null; fieldClass = fieldClass.getSuperclass()) {
if (classFilterForNullables.containsKey(fieldClass)) {
Predicate<Object> handle = classFilterForNullables.get(fieldClass);
if (handle.test(fieldValue)) {
return true;
} else {
return false;
}
}
}
if (clean(field.get(arg))) { // decent to contained objects
field.set(arg, null);
} else {// non clean-able child exists
return false;
}
return true;
}
private void fillPredicates() {
nullableFilters(String.class, Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class,
Float.class, Double.class, Void.class, LocalDateTime.class, LocalDate.class, LocalTime.class,
OffsetDateTime.class, OffsetTime.class);
classFilterForNullables.put(NullableEmbeddedCleanerImpl.class, n -> true); // always
// filter
}
private void nullableFilters(Class<?>... cs) {
for (Class<?> c : cs) {
classFilterForNullables.put(c, o -> false);
}
}
#SuppressWarnings("unchecked")
final private <T> void collection(Class<T> c, Predicate<T> fun) {
collectionMap.put((Class<?>) c, ((Predicate<Object>) fun));
}
}

Searching for a String in an Array of Objects

I have a Object that contains an ArrayList of self referntial objects. Each Object in that ArrayList contains the same structre upto n degrees. Now i have to search for a string in the structure and if found i have to print all the way up to the root. Here is a sample
MyClass {
string name;
ArrayList<MyClass> subClasses;
}
What data structure would be best to do this. Or do i not need one to use it.
Kind Regards
You could have a method on MyClass like below
public List<String> findPathOfName(String nameToFind) {
List<String> result = new ArrayList<String>();
if (nameToFind.equals(name)) {
result.add(name);
} else {
for (MyClass aSubClass: subClasses) {
List<String> subResult = aSubClass.findPathOfName(nameToFind);
if (!subResult.isEmpty()) {
result.add(name);
result.addAll(subResult);
break;
}
}
}
return result;
}
basically recursively go through the structure and find the path. Returned list would contain the path like personA/personB/etc..
This is http://en.wikipedia.org/wiki/Composite_pattern. Try my version
static class MyClass {
String name;
List<MyClass> subClasses;
MyClass(String name) {
this.name = name;
}
String search(String s, String path) {
if (!path.isEmpty()) {
path += "->";
}
path += name;
if (!s.equals(name)) {
if (subClasses == null) {
return null;
}
for (MyClass c : subClasses) {
return c.search(s, path);
}
}
return path;
}
}
public static void main(String[] args) throws Exception {
MyClass c1 = new MyClass("c1");
MyClass c2 = new MyClass("c2");
MyClass c3 = new MyClass("c3");
c1.subClasses = Arrays.asList(c2);
c2.subClasses = Arrays.asList(c3);
System.out.println(c1.search("c3", ""));
}
output
c1->c2->c3

How to convert string result of enum with overridden toString() back to enum?

Given the following java enum:
public enum AgeRange {
A18TO23 {
public String toString() {
return "18 - 23";
}
},
A24TO29 {
public String toString() {
return "24 - 29";
}
},
A30TO35 {
public String toString() {
return "30 - 35";
}
},
}
Is there any way to convert a string value of "18 - 23" to the corresponding enum value i.e. AgeRange.A18TO23 ?
Thanks!
The best and simplest way to do it is like this:
public enum AgeRange {
A18TO23 ("18-23"),
A24TO29 ("24-29"),
A30TO35("30-35");
private String value;
AgeRange(String value){
this.value = value;
}
public String toString(){
return value;
}
public static AgeRange getByValue(String value){
for (final AgeRange element : EnumSet.allOf(AgeRange.class)) {
if (element.toString().equals(value)) {
return element;
}
}
return null;
}
}
Then you just need to invoke the getByValue() method with the String input in it.
You could always create a map from string to value - do so statically so you only need to map it once, assuming that the returned string remains the same over time. There's nothing built-in as far as I'm aware.
According to effective java (2nd ed) item 30, it can be (it is much faster than the loop)
public enum AgeRange {
A18TO23("18-23"),
A24TO29("24-29"),
A30TO35("30-35");
private final String value;
AgeRange(String value){
this.value = value;
}
#Override public String toString(){
return value;
}
private static final Map<String, AgeRange> stringToEnum =
new HashMap<String, AgeRange>();
static {
for (AgeRange r : values()) {
stringToEnum.put(r.toString(), r);
}
}
public static AgeRange getByValue(String value){
return stringToEnum.get(value);
}
}
for (AgeRange ar: EnumSet.allOf(AgeRange)) {
if (ar.toString().equals(inString)) {
myAnswer = ar;
break;
}
}
Or something like that? Just typed in, haven't run through a compiler. Forgive (comment on) typos...
Or use logic like this to build a map once. Avoid iteration at runtime. Good idea, Jon.
The class overrides "toString()" - so, to get the reverse operation, you need to override valueOf() to translate the output of toString() back to the Enum values.
public enum AgeRange {
A18TO23 {
public String toString() {
return "18 - 23";
}
public AgeRange valueOf (Class enumClass, String name) {
return A18T023
}
},
.
.
.
}
Buyer beware - uncompiled and untested...
The mechanism for toString() and valueOf() is a documented part of the API
You could try something like the following?
static AgeRange fromString(String range) {
for (AgeRange ageRange : values()) {
if (range.equals(ageRange.toString())) {
return ageRange;
}
}
return null;
}
Or, as others suggested, using a caching approach:
private static Map<String, AgeRange> map;
private static synchronized void registerAgeRange(AgeRange ageRange) {
if (map == null) {
map = new HashMap<String, AgeRange>();
}
map.put(ageRange.toString(), ageRange);
}
AgeRange() {
registerAgeRange(this);
}
static AgeRange fromString(String range) {
return map.get(range);
}

Categories