Concatenate object values regarding name of fields in alphabetical order - java

I'm looking for a method to concatenate object values regarding name of fields in alphabetical order.
Example:
public Class Request {
private String number;
private String amount;
private String currency;
}
Request request = new Request();
request.setNumber("tata");
request.setCurrency("toto");
With this, my method should return tototata.
Method must be generic:
public static String concatenate(Object object) { ...}
null values must not be concatenated.
I already checked out Apache Commons BeanUtils and Java 8 streams, but found nothing nice.

Thanks you Andrew Tobilko, i was doing this (working)
public static String concatenateAlphabetically(Object object) {
Map<String, String> map = null;
try {
map = BeanUtils.describe(object);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
// remove class attribute generating from BeanUtils.describe
map.remove("class");
map.values().removeAll(Collections.singleton(null));
Map<String, String> treeMap = new TreeMap<String, String>(map);
return treeMap.values().stream().collect(Collectors.joining());
}
But i don't like to use BeanUtils like this, i prefer your method.
I just add f.setAccessible(true); to access to private fields

You may write this by iterating over all declared fields in the given object.
public static String concatenate(Object object) {
return Arrays.stream(object.getClass().getDeclaredFields())
.filter(f -> f.getType() == String.class)
.sorted(Comparator.comparing(Field::getName))
.map(f -> {
try { return (String)f.get(object); }
catch (IllegalAccessException e) { return null; }
})
.filter(Objects::nonNull)
.collect(Collectors.joining());
}

Related

How to return in Java 8 a Map with one entry removed

Using Java 8 I have a Map<String, String> and I want to use a method of one of the standard libraries to return a Map with a specified entry removed.
So essentially I'm looking for a way to achieve just by a function call or by function concatenation the following (hypothetical) method of Map:
Map<String, String> removed(String key) {
this.remove(key);
return this;
}
The whole thing would help me to convert a Map of a Bean into a pretty string in one line
The version that does not modify the input map could look like this.
return map.entrySet().stream()
.filter(e -> !e.getKey().equals(other))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Yes, I do not think it can get easier than that.
If all you want to do, is to implement a toString() method skipping the "class" property, you could do that straight-forwardly without manipulating the Map:
#Override
public String toString() {
return BeanUtils.describe(this).entrySet().stream()
.filter(e -> !e.getKey().equals("class"))
.map(Object::toString)
.collect(Collectors.joining("\n", super.toString()+":\n", ""));
}
But to me, not being able to exclude the class property in the first place, looks like an unfortunate omission. Consider:
public class MyBeanUtils {
public static Map<String,Object> describe(Object o) {
try {
return describe(o, Introspector.getBeanInfo(o.getClass()));
} catch (IntrospectionException ex) {
throw new IllegalStateException(ex);
}
}
public static Map<String,Object> describe(Object o, Class<?> stopClass) {
try {
return describe(o, Introspector.getBeanInfo(o.getClass(), stopClass));
} catch (IntrospectionException ex) {
throw new IllegalStateException(ex);
}
}
private static Map<String,Object> describe(Object o, BeanInfo beanInfo) {
Map<String,Object> map=new HashMap<>();
for(PropertyDescriptor fd: beanInfo.getPropertyDescriptors()) {
if(fd.getReadMethod()!=null) try {
map.put(fd.getName(), fd.getReadMethod().invoke(o));
} catch(IllegalAccessException | InvocationTargetException ex){}
}
return map;
}
}
Now, by specifying Object.class as stop class, we exclude its properties, which is exactly the class property defined by Object.getClass():
#Override
public String toString() {
return MyBeanUtils.describe(this, Object.class).entrySet().stream()
.map(Object::toString)
.collect(Collectors.joining("\n", super.toString()+":\n", ""));
}
This even enables another opportunity. If we assume that super.toString() already cares for all properties of the super class hierarchy, we can specify our own superclass as stop class to only add properties defined in our class:
public class BeanExample extends JButton {
String foo = "some string";
int bar = 42;
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
public int getBar() {
return bar;
}
public void setBar(int bar) {
this.bar = bar;
}
#Override
public String toString() {
return MyBeanUtils.describe(this, getClass().getSuperclass()).entrySet().stream()
.map(Object::toString)
.collect(Collectors.joining("\n", super.toString()+":\n", ""));
}
}
→
BeanExample[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.5,border=javax.swing.plaf.BorderUIResource$CompoundBorderUIResource#b1bc7ed,flags=296,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=2,left=14,bottom=2,right=14],paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=true,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=,defaultCapable=true]:
bar=42
foo=some string

How to create map of java POJO class/ Json String having primitive data?

I want to make a Map (String ,Object) like this
{AssessmentId=0, Physical_name='ram', Physical_height=20, Physical_weight=60}
from my Pojo Class - InitialAssessment
public class InitialAssessment {
private long AssessmentId;
private String physical_name;
private String physical_gender;
private int physical_height;
private float physical_weight;
// all getter And setter is Created here
}
without using any external Library like Gson etc.
You can use this approach:
public Map getMapFromPojo(InitialAssessment assessment) throws Exception {
Map<String, Object> map = new HashMap<>();
if (assessment != null) {
Method[] methods = assessment.getClass().getMethods();
for (Method method : methods) {
String name = method.getName();
if (name.startsWith("get") && !name.equalsIgnoreCase("getClass")) {
Object value = "";
try {
value = method.invoke(assessment);
map.put(name.substring(name.indexOf("get") + 3), value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return map;
}
return null;
}
It will give you map for pojo class like this:
Output:
{AssessmentId=0, Physical_name='ram', Physical_gender='Male' , Physical_height=20, Physical_weight=60}

Use HashMap to create dynamic function call

I am trying to create a function call using hashmap.
For example,
Hashmap--
"a" -> "b"
"c" -> "d"
Now I should parse this Hashmap and create a function like this-
someFun("{a:#,c:#}",new SomeClass(b),new SomeClass(d));
As you can see, a and c are keys of hashmap(first argument) ; b and d are used to create objects (second argument and so on..)
someFun parameters depend on HashMap size..
I am confused! Because I can loop through the map to get Keys and easily create the first argument.
For the second argument, I can use the value to create Objects.
But now how do I add these together to make the function call as specified?
Any help would be very much appreciated :)
P.S: My question is not about getting values/keys from hashmap,but using them to create a function call something as specified.I am not allowed to change someFun consider it as API call.
Is it something like this, that you need:
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map.Entry;
public class Draft {
public static class SomeClass{
final private String val;
public SomeClass(String val) {
this.val = val;
}
}
public void someFun(String str, SomeClass ... classes) {
System.out.println("someFun" + str + Arrays.toString(classes));
}
public static void main(String[] args) {
HashMap<String, String> keyToParam = new HashMap<>();
keyToParam.put("a", "b");
keyToParam.put("c", "d");
String strArg = null;
SomeClass[] classes = new SomeClass[keyToParam.size()];
int pointer = 0;
for(Entry<String, String> entry: keyToParam.entrySet()) {
strArg += entry.getKey() + ":#";
classes[pointer++] = new SomeClass(entry.getValue());
}
new Draft().someFun(strArg, classes);
}
}
First, you should define function like this:
public void someFun(String str, SomeClass[] someClasses) {
// do something
}
Or this:
public void someFun(String str, SomeClass... someClass) {
// do something
}
The former would be better because it's easy to call it by Java Reflection.
Then go through the hashmap and concentrate all keys to a string someString as the first parameter. While doing the iteration, you put all the values into an array someClasses as the second parameter.
Finally get the method and invoke it by (assume that we use SomeObject someObject to call the function):
Method method = SomeObject.getClass().getMethod("someFun");
method.invoke(someObject, new Object[] {someString, someClasses});
To get the HapsMap Key values
HashMap<Object, Object> hashMap= new HashMap<Object,Object>();
...
Set<Object> keyValueSet=hashMap.keySet();
for ( Object keyValue : keyValueSet) {
//you get the key from keyValue and the corresponding value from hashMap using this
hashMap.get(keyValue);
}
The rest is your logic, you can use the values in any place you want.
Try this way...
try {
Object obj = new Object();// Create a new instance of the class that contain your method.
Method m = obj.getClass().getMethod("methodName", param1.class, param2.class, ..);
// In your case Method m = obj.getClass().getMethod("someFun", String.class,SomeClass.class,SomeClass.class);
m.invoke(obj, "{a:#,c:#}", new SomeClass(b),new SomeClass(d));
}catch (SecurityException e) {
// ...
} catch (NoSuchMethodException e) {
// ...
}catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
Method implementation :
public static void someFun(String name, SomeClass classes ...) {
for (SomeClass cls : classes) {
//Logic here
}
}

flexjson deserialize property string with dot "." inside

I'm trying to use flexjson to deserialize a string I get from a web call. The problem is that a few elements in there have a dot in the property/key for example:
[{...
"contact.name": "Erik Svensson",
"contact.mail": "erik.svensson#foo.bar",
"contact.phone": "0731123243",
...}]
Now everything else falls in place except these strings with the dots, they end up null in my target class. I'm guessing it's because it doesn't know what to map them to as I can't declare a variable in my container class that has a dot.
This is the code I'm runnign to deserialize now,
mData = new JSONDeserializer<List<Thing>>()
.use("values", Thing.class)
.deserialize(reader);
How do I modify this to catch the strings with the dot and put them in my Things class as:
String contactName;
String contactMail;
String contactPhone;
// getters&setters
Note I don't have any control over the Serialization..
OK So I've solved this but I had to abandon flexJson. Searched all over the place for a simple way but couldn't find one.
Instead I went with Jackson and this is what I ended up with:
ObjectMapper mapper = new ObjectMapper();
mThings = mapper.readValue(url, new TypeReference<List<Thing>>() {});
And in my class Thing:
#JsonProperty("contact.name")
private String contactName;
#JsonProperty("contact.mail")
private String contactMail;
#JsonProperty("contact.phone")
private String contactPhone;
// getters and setters..
If anyone knows how to do this with FlexJson feel free to post an answer, I would like to see it.
As I was curious, too, if this type of assignment can be done easily, I've played with some code, and this is what I came up with. (I'm posting it here because maybe it's helpful for somebody having some related question, or just as a point to start from.)
The PrefixedObjectFactory (see below) will cut off a fixed prefix from the JSON object's field name and use this name to find a matching bean property. The code can be easily changed to do a replacement instead (e.g. setting the first letter after a . to uppercase and remove the .)
It can be used like this:
List<Thing> l = new JSONDeserializer<List<Thing>>().use("values", new PrefixedObjectFactory(Thing.class, "contact.")).deserialize(source);
The code:
import flexjson.ObjectBinder;
import flexjson.ObjectFactory;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Type;
import java.util.Map;
public class PrefixedObjectFactory<T> implements ObjectFactory {
protected Class<T> clazz;
protected String prefix;
public PrefixedObjectFactory(Class<T> c, String prefix) {
this.clazz = c;
this.prefix = (prefix == null) ? "" : prefix;
}
#Override
public Object instantiate(ObjectBinder context, Object value, Type targetType, Class targetClass) {
try {
Class useClass = this.clazz;
T obj = (T)useClass.newInstance();
if (value instanceof Map) {
// assume that the value is provided as a map
Map m = (Map)value;
for (Object entry : m.entrySet()) {
String propName = (String)((Map.Entry)entry).getKey();
Object propValue = ((Map.Entry)entry).getValue();
propName = fixPropertyName(propName);
propValue = fixPropertyValue(propValue);
assignValueToProperty(useClass, obj, propName, propValue);
}
} else {
// TODO (left out here, to keep the code simple)
return null;
}
return obj;
} catch (Exception ex) {
return null;
}
}
protected String fixPropertyName(String propName) {
if (propName.startsWith(this.prefix)) {
propName = propName.substring(this.prefix.length());
}
return propName;
}
protected Object fixPropertyValue(Object propValue) {
return propValue;
}
protected PropertyDescriptor findPropertyDescriptor(String propName, Class clazz) {
try {
return new PropertyDescriptor(propName, clazz);
} catch (Exception ex) {
return null;
}
}
protected void assignValueToProperty(Class clazz, Object obj, String propName, Object propValue) {
try {
PropertyDescriptor propDesc = findPropertyDescriptor(propName, clazz);
if (propDesc != null) {
propDesc.getWriteMethod().invoke(obj, propValue);
}
} catch (Exception ex) {
}
}
}

Java—how can I dynamically reference an object's property?

In javascript, I can do this:
function MyObject(obj) {
for (var property in obj) {
this[property] = obj[property];
}
}
Can I do anything close in Java?
class MyObject {
String myProperty;
public MyObject(HashMap<String, String> props) {
// for each key in props where the key is also the name of
// a property in MyObject, can I assign the value to this.[key]?
}
}
Not that I disagree with Joel's answer, but I do not think it is not quite that difficult, if you essentially just want a best effort. Essentially check if it is there, and if it is try to set. If it works great if not, oh well we tried. For example:
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class MyObject {
protected String lorem;
protected String ipsum;
protected int integer;
public MyObject(Map<String, Object> valueMap){
for (String key : valueMap.keySet()){
setField(key, valueMap.get(key));
}
}
private void setField(String fieldName, Object value) {
Field field;
try {
field = getClass().getDeclaredField(fieldName);
field.set(this, value);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Map<String, Object> valueMap = new HashMap<String, Object>();
valueMap.put("lorem", "lorem Value");
valueMap.put("ipsum", "ipsum Value");
valueMap.put("integer", 100);
valueMap.put("notThere", "Nope");
MyObject f = new MyObject(valueMap);
System.out.println("lorem => '"+f.lorem+"'");
System.out.println("ipsum => '"+f.ipsum+"'");
System.out.println("integer => '"+f.integer+"'");
}
}
Yes, you can do it by reflection with something along the following lines:
/**
* Returns a list of all Fields in this object, including inherited fields.
*/
private List<Field> getFields() {
List<Field> list = new ArrayList<Field>();
getFields(list, getClass());
return list;
}
/**
* Adds the fields of the provided class to the List of Fields.
* Recursively adds Fields also from super classes.
*/
private List<Field> getFields(List<Field> list, Class<?> startClass) {
for (Field field : startClass.getDeclaredFields()) {
list.add(field);
}
Class<?> superClass = startClass.getSuperclass();
if(!superClass.equals(Object.class)) {
getFields(list, superClass);
}
}
public void setParameters(Map<String, String> props) throws IllegalArgumentException, IllegalAccessException {
for(Field field : getFields()) {
if (props.containsKey(field.getName())) {
boolean prevAccessible = field.isAccessible();
if (!prevAccessible) {
/*
* You're not allowed to modify this field.
* So first, you modify it to make it modifiable.
*/
field.setAccessible(true);
}
field.set(this, props.get(field.getName()));
/* Restore the mess you made */
field.setAccessible(prevAccessible);
}
}
}
However, if you are not very familiar with Java, this approach should be avoided if at all possible, as it is somewhat dangerous and error prone. For instance, there is no guarantee that the Field you are attempting to set are actually expecting a String. If it is the case that they are not, your program will crash and burn.
First, I would use a map if at all possible:
class MyObject {
// String myProperty; // ! not this
HashMap<String,String> myProperties; // use this instead
}
but let's say you wanted to set the fields dynamically.
public MyObject(HashMap<String, String> props) {
for (Map.Entry<String,String> entry : props.entrySet()) {
Field field = this.getClass().getField(entry.getKey());
field.set(this, entry.getValue());
}
}
of course, you will want to use a try/catch in the above constructor.
Well, if you really want to go down the reflection raod, then I suggest to have a look at the Introspector class and get the list of PropertyDescriptors from the BeanInfo.

Categories

Resources