Get list of attribute values from list of beans - java

I have a list of beans and want to obtain a list of values (given a specific attribute).
For instance, I have a list of document definitions and I want to get a list of codes:
List<DDocumentDef> childDefs = MDocumentDef.getChildDefinitions(document.getDocumentDef());
Collection<String> childCodes = new HashSet<String>();
for (DDocumentDef child : childDefs) {
childCodes.add(child.getCode());
}
Is there any more compact solution? Reflection, anonymous inner classes ...?
Thanks in advance

I feel fine with your current approach.
But if you want to add a library (e.g. apache commons-collection and commons-beanutils) or you already have added it, you can do it this way:
// create the transformer
BeanToPropertyValueTransformer transformer = new BeanToPropertyValueTransformer("code" );
// transform the Collection
Collection childCodes = CollectionUtils.collect( childDefs , transformer );
the Guava lib from google provides a similar api.

There is no other way to do this with standard Java API. However, if you are comfortable, you can use Guava's Lists.transform method:
Function<DDocumentDef, String> docToCodes =
new Function<DDocumentDef, String>() {
public String apply(DDocumentDef docDef) {
return docDef.getCode();
}
};
List<String> codes = Lists.transform(childDefs, docToCodes);
Or, wait until Java 8 is out, and then you can use lambdas and streams for this:
List<DDocumentDef> childDefs = ...
List<String> childCodes = childDefs.stream()
.map(docDef -> docDef.getCode())
.collect(Collectors.toCollection(HashSet::new));
Now it's upto you to decide, which one do you prefer, and which one do you think is shorter.

Related

How to add list of items to an ArrayList<String> in java?

I have list of words which I need to load to ArrayList< String >
prefix.properties
vocab\: = http://myweb.in/myvocab#
hydra\: = http://www.w3.org/ns/hydra/core#
schema\: = http://schema.org/
"vocab:" is actually "vocab:" .Slash(\) is used to read colon(:) character because it is special character.
Dictionary.java
public class Dictionary {
public static ArrayList<String> prefix = new ArrayList<>();
static {
Properties properties = new Properties();
InputStream input = null;
input = ClassLoader.getSystemResourceAsStream("prefix.properties");
System.out.println(input!=null);
try {
properties.load(input);
} catch (IOException e) {
e.printStackTrace();
}
Set<Map.Entry<Object, Object>> entries = properties.entrySet();
for(Map.Entry<Object, Object> E : entries)
{
prefix.add(E.getKey().toString());
prefix.add(E.getValue().toString());
}
}
}
In Dictionary.java , ArrayList prefix will have
prefix = [
"vocab:",
"http://myweb.in/myvocab#",
"hydra:",
"http://www.w3.org/ns/hydra/core#",
"schema:",
"http://schema.org/"
]
I am querying some data in another class.
For eg:
public class QueryClass
{
public ArrayList<String> queryResult(String findKey)
{
ArrayList<String> result = new ArrayList<String>();
ArrayList<String> prefix = Dictionary.prefix;
Iterator<String> iterator = prefix.iterator();
while (iterator.hasNext())
{
String currentKey = iterator.next()+findKey;
/**
Here my logic to search data with this currentKey
*/
}
return result;
}
}
Problem :
I want to avoid this method to load from .properties file because there is possibility of odd number of elements can be present while .properties file provide (key,value) pair way to store data.
Reason why I have to load from separate file ? Because In future I will have to add more keywords/String thats why I put it in prefix.properties file.
Is there any alternative way to do this?
Do not re-invent the wheel.
If you can define the file format, then just go for java properties.
You see, the Properties class has a method getProperty(String, String) where the second argument can be used to pass a default value for example. That method could be used in order to fetch keys that don't come with values.
I would be really careful about inventing your own format; instead I would look into ways of re-using what is already there. Writing code is similar to building roads: people forget that each new road that is built translates to maintenance efforts in the future.
Besides: you add string values to a list of strings by calling list.add(strValue). That is all that is to that.
Edit on your comment: when "java properties" are not what you are looking for; then consider using other formats. For example you could be persisting your data in some JSON based format. And then just go for some existing JSON parser. Actually, your data almost looks like JSON already.
I'm not sure why you need to use ArrayList but if you want to pass these property keys/values, there are 2 better ways:
Use Properties itself.
Convert to HashMap.

Find intersection between collections with different objects

I have list of custom objects like below:
List<CustomObject> existingValues
And another collection with ids that has been sent from client and contains ids of CustomObject mentoioned above Set<Long> ids.
My goal is to return collection with CustomObject that will contains only elements where ids intersect.
I can simply do this with nested for each cycles. But it looks a bit ugly.
In SQL I can do similar stuff with query:
select * where customobject.id in (some ids...)
In wich way it can be achived with lamdaj or guava?
With Guava this is done as follows:
final Set<Long> ids = ...; //initialize correctly
List<CustomObject> results = FluentIterable.from(existingValues).filter(new Predicate<CustomObject>() {
#Override
public boolean apply(final CustomObject input) {
return ids.contains(input.getId());
}
}).toList();
With Java 8 you can achieve this with a stream filter:
List<CustomObject> collect = existingValues.stream()
.filter(object -> ids.contains(object.getId()))
.collect(Collectors.toList());
To get familiar with java streams I recommand the offical Oracle Tutorial.
Yes as #wuethrich44 says in Java 8 the solution is:
List<CustomObject> collect = existingValues.stream()
.filter(object -> ids.contains(object.getId()))
.collect(Collectors.toList());
And in the case you have a version older than Java 8:
List<CustomObject> collect = new ArrayList<CustomObject>();
for(CustomObject object: existingValues) {
if(ids.contains(object.getId())) {
collect.add(object);
}
}
And for version older than Java 5:
List<CustomObject> collect = new ArrayList<CustomObject>();
Iterator<CustomObject> iterator = existingValues.iterator();
while(iterator.hasNext()) {
CustomObject object = iterator.next();
if(ids.contains(object.getId())) {
collect.add(object);
}
}
but the version with stream is better: faster in term of execution time, less verbose, and more readable if you are use to it
If you can use my xpresso library you can use list comprehensions with lambda expressions like this:
list<CustomObject> filtered = x.list(x.<CustomObject>yield().forEach(existingValues).when(x.lambdaP("x : f1(f0(x))",x.invoke("getId"),x.in(ids))));

Codemodel: generic types generation in a loop .narrow()?

I am using sun-codemodel to generate code. I have problem with generics. I know that to generate something like
LinkedList<String>,
I need to use
JType jtype = jCodeModel.ref("LinkedList").narrow(jCodeModel.ref("String"));
However, how do I create something more general, for more than one generic type?
HashMap<String,Integer>
I would like to do it in the loop so that it supports any number of arguments in custom classes, but for the code like:
for(String name: names()){
returnTypeClass = jCodeModel.ref(name).narrow(jCodeModel.ref(name));
}
the output is something like this:
JNarrowedClass(JCodeModel$JReferencedClass(HashMap)<Integer>)<String>
I'm unfamiliar with CodeModel, but looking at the API documentation it seems there's a varargs overload: narrow(JClass...). Presumably this is used for resolving multiple type parameters. So in the case of HashMap<String, Integer>, you would do:
JType jtype = jCodeModel.ref("HashMap").narrow(
jCodeModel.ref("String"),
jCodeModel.ref("Integer")
);
And generalizing this to your loop:
Collection<JClass> typeArgClasses = new ArrayList<>();
for (String name : names()) {
typeArgClasses.add(jCodeModel.ref(name));
}
JType jtype = jCodeModel
.ref(typeName)
.narrow(typeArgClasses.toArray(new JClass[typeArgClasses.size()]);

Add multiple fields to Java 5 HashSet at once?

Is there a better way to do this so I don't have to have 50 ".add()"s in there? Like a comma separated list or something (like JavaScript arrays).
private static final Set<String> validStates = new HashSet<String>();
validStates.add("AL");
validStates.add("AK");
validStates.add("AZ");
validStates.add("AR");
validStates.add("CA");
validStates.add("CO");
validStates.add("CT");
validStates.add("DE");
validStates.add("DC");
validStates.add("FL");
validStates.add("GA");
validStates.add("HI");
validStates.add("ID");
validStates.add("IL");
validStates.add("IN");
validStates.add("IA");
validStates.add("KS");
validStates.add("KY");
validStates.add("LA");
validStates.add("ME");
validStates.add("MD");
validStates.add("MA");
validStates.add("MI");
validStates.add("MN");
validStates.add("MS");
validStates.add("MO");
validStates.add("MT");
validStates.add("NE");
validStates.add("NV");
validStates.add("NH");
validStates.add("NJ");
validStates.add("NM");
validStates.add("NY");
validStates.add("NC");
validStates.add("ND");
validStates.add("OH");
validStates.add("OK");
validStates.add("OR");
validStates.add("PA");
validStates.add("RI");
validStates.add("SC");
validStates.add("SD");
validStates.add("TN");
validStates.add("TX");
validStates.add("UT");
validStates.add("VT");
validStates.add("VA");
validStates.add("WA");
validStates.add("WV");
validStates.add("WI");
validStates.add("WY");
Something like:
validStates.add("AL", "AK", "...");
The HashSet has a constructor taking a Collection. The Arrays#asList() takes arguments as varargs and returns a List (which is a Collection). So, you could do it as follows:
validStates = new HashSet<String>(Arrays.asList("AL", "AK", ".."));
It makes however more sense to have them in some properties file or in a DB which you load by one or two lines of code so that you don't need to hardcode them all in Java.
If you were on Java 8+, you could just use Stream#of().
validStates = Stream.of("AK", "AL", "..").collect(Collectors.toSet());
If you fancy using the excellent Google Guava library, you can use:
Set<String> validStates = Sets.newHashSet("AL", "AK", "...");
You could have a static String[] with all the states, then iterate over the array:
String states[] = {"AL","AK","AZ","AR",...etc...};
for (String currState : states) {
validStates.add(currState);
}
I don't remember if this "foreach" construct came in 1.5 or 1.6....
HashSet<String> hs = Sets.newHashSet("abc","xyz");

How to convert a Java object (bean) to key-value pairs (and vice versa)?

Say I have a very simple java object that only has some getXXX and setXXX properties. This object is used only to handle values, basically a record or a type-safe (and performant) map. I often need to covert this object to key value pairs (either strings or type safe) or convert from key value pairs to this object.
Other than reflection or manually writing code to do this conversion, what is the best way to achieve this?
An example might be sending this object over jms, without using the ObjectMessage type (or converting an incoming message to the right kind of object).
Lots of potential solutions, but let's add just one more. Use Jackson (JSON processing lib) to do "json-less" conversion, like:
ObjectMapper m = new ObjectMapper();
Map<String,Object> props = m.convertValue(myBean, Map.class);
MyBean anotherBean = m.convertValue(props, MyBean.class);
(this blog entry has some more examples)
You can basically convert any compatible types: compatible meaning that if you did convert from type to JSON, and from that JSON to result type, entries would match (if configured properly can also just ignore unrecognized ones).
Works well for cases one would expect, including Maps, Lists, arrays, primitives, bean-like POJOs.
There is always apache commons beanutils but of course it uses reflection under the hood
Code generation would be the only other way I can think of. Personally, I'd got with a generally reusable reflection solution (unless that part of the code is absolutely performance-critical). Using JMS sounds like overkill (additional dependency, and that's not even what it's meant for). Besides, it probably uses reflection as well under the hood.
This is a method for converting a Java object to a Map
public static Map<String, Object> ConvertObjectToMap(Object obj) throws
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException {
Class<?> pomclass = obj.getClass();
pomclass = obj.getClass();
Method[] methods = obj.getClass().getMethods();
Map<String, Object> map = new HashMap<String, Object>();
for (Method m : methods) {
if (m.getName().startsWith("get") && !m.getName().startsWith("getClass")) {
Object value = (Object) m.invoke(obj);
map.put(m.getName().substring(3), (Object) value);
}
}
return map;
}
This is how to call it
Test test = new Test()
Map<String, Object> map = ConvertObjectToMap(test);
Probably late to the party. You can use Jackson and convert it into a Properties object. This is suited for Nested classes and if you want the key in the for a.b.c=value.
JavaPropsMapper mapper = new JavaPropsMapper();
Properties properties = mapper.writeValueAsProperties(sct);
Map<Object, Object> map = properties;
if you want some suffix, then just do
SerializationConfig config = mapper.getSerializationConfig()
.withRootName("suffix");
mapper.setConfig(config);
need to add this dependency
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-properties</artifactId>
</dependency>
When using Spring, one can also use Spring Integration object-to-map-transformer. It's probably not worth adding Spring as a dependency just for this.
For documentation, search for "Object-to-Map Transformer" on http://docs.spring.io/spring-integration/docs/4.0.4.RELEASE/reference/html/messaging-transformation-chapter.html
Essentially, it traverses the entire object graph reachable from the object given as input, and produces a map from all primitive type/String fields on the objects. It can be configured to output either:
a flat map: {rootObject.someField=Joe, rootObject.leafObject.someField=Jane}, or
a structured map: {someField=Joe, leafObject={someField=Jane}}.
Here's an example from their page:
public class Parent{
private Child child;
private String name;
// setters and getters are omitted
}
public class Child{
private String name;
private List<String> nickNames;
// setters and getters are omitted
}
Output will be:
{person.name=George, person.child.name=Jenna,
person.child.nickNames[0]=Bimbo . . . etc}
A reverse transformer is also available.
With Java 8 you may try this :
public Map<String, Object> toKeyValuePairs(Object instance) {
return Arrays.stream(Bean.class.getDeclaredMethods())
.collect(Collectors.toMap(
Method::getName,
m -> {
try {
Object result = m.invoke(instance);
return result != null ? result : "";
} catch (Exception e) {
return "";
}
}));
}
JSON, for example using XStream + Jettison, is a simple text format with key value pairs. It is supported for example by the Apache ActiveMQ JMS message broker for Java object exchange with other platforms / languages.
Simply using reflection and Groovy :
def Map toMap(object) {
return object?.properties.findAll{ (it.key != 'class') }.collectEntries {
it.value == null || it.value instanceof Serializable ? [it.key, it.value] : [it.key, toMap(it.value)]
}
}
def toObject(map, obj) {
map.each {
def field = obj.class.getDeclaredField(it.key)
if (it.value != null) {
if (field.getType().equals(it.value.class)){
obj."$it.key" = it.value
}else if (it.value instanceof Map){
def objectFieldValue = obj."$it.key"
def fieldValue = (objectFieldValue == null) ? field.getType().newInstance() : objectFieldValue
obj."$it.key" = toObject(it.value,fieldValue)
}
}
}
return obj;
}
Use juffrou-reflect's BeanWrapper. It is very performant.
Here is how you can transform a bean into a map:
public static Map<String, Object> getBeanMap(Object bean) {
Map<String, Object> beanMap = new HashMap<String, Object>();
BeanWrapper beanWrapper = new BeanWrapper(BeanWrapperContext.create(bean.getClass()));
for(String propertyName : beanWrapper.getPropertyNames())
beanMap.put(propertyName, beanWrapper.getValue(propertyName));
return beanMap;
}
I developed Juffrou myself. It's open source, so you are free to use it and modify. And if you have any questions regarding it, I'll be more than happy to respond.
Cheers
Carlos
You can use the java 8 stream filter collector properties,
public Map<String, Object> objectToMap(Object obj) {
return Arrays.stream(YourBean.class.getDeclaredMethods())
.filter(p -> !p.getName().startsWith("set"))
.filter(p -> !p.getName().startsWith("getClass"))
.filter(p -> !p.getName().startsWith("setClass"))
.collect(Collectors.toMap(
d -> d.getName().substring(3),
m -> {
try {
Object result = m.invoke(obj);
return result;
} catch (Exception e) {
return "";
}
}, (p1, p2) -> p1)
);
}
You could use the Joda framework:
http://joda.sourceforge.net/
and take advantage of JodaProperties. This does stipulate that you create beans in a particular way however, and implement a specific interface. It does then however, allow you to return a property map from a specific class, without reflection. Sample code is here:
http://pbin.oogly.co.uk/listings/viewlistingdetail/0e78eb6c76d071b4e22bbcac748c57
If you do not want to hardcode calls to each getter and setter, reflection is the only way to call these methods (but it is not hard).
Can you refactor the class in question to use a Properties object to hold the actual data, and let each getter and setter just call get/set on it? Then you have a structure well suited for what you want to do. There is even methods to save and load them in the key-value form.
The best solution is to use Dozer. You just need something like this in the mapper file:
<mapping map-id="myTestMapping">
<class-a>org.dozer.vo.map.SomeComplexType</class-a>
<class-b>java.util.Map</class-b>
</mapping>
And that's it, Dozer takes care of the rest!!!
Dozer Documentation URL
There is of course the absolute simplest means of conversion possible - no conversion at all!
instead of using private variables defined in the class, make the class contain only a HashMap which stores the values for the instance.
Then your getters and setters return and set values into and out of the HashMap, and when it is time to convert it to a map, voila! - it is already a map.
With a little bit of AOP wizardry, you could even maintain the inflexibility inherent in a bean by allowing you to still use getters and setters specific to each values name, without having to actually write the individual getters and setters.
My JavaDude Bean Annotation Processor generates code to do this.
http://javadude.googlecode.com
For example:
#Bean(
createPropertyMap=true,
properties={
#Property(name="name"),
#Property(name="phone", bound=true),
#Property(name="friend", type=Person.class, kind=PropertyKind.LIST)
}
)
public class Person extends PersonGen {}
The above generates superclass PersonGen that includes a createPropertyMap() method that generates a Map for all properties defined using #Bean.
(Note that I'm changing the API slightly for the next version -- the annotation attribute will be defineCreatePropertyMap=true)
You should write a generic transformation Service! Use generics to keep it type free (so you can convert every object to key=>value and back).
What field should be the key? Get that field from the bean and append any other non transient value in a value map.
The way back is pretty easy. Read key(x) and write at first the key and then every list entry back to a new object.
You can get the property names of a bean with the apache commons beanutils!
If you really really want performance you can go the code generation route.
You can do this on your on by doing your own reflection and building a mixin AspectJ ITD.
Or you can use Spring Roo and make a Spring Roo Addon. Your Roo addon will do something similar to the above but will be available to everyone who uses Spring Roo and you don't have to use Runtime Annotations.
I have done both. People crap on Spring Roo but it really is the most comprehensive code generation for Java.
One other possible way is here.
The BeanWrapper offers functionality to set and get property values (individually
or in bulk), get property descriptors, and to query properties to determine if they
are readable or writable.
Company c = new Company();
BeanWrapper bwComp = BeanWrapperImpl(c);
bwComp.setPropertyValue("name", "your Company");
If it comes to a simple object tree to key value list mapping, where key might be a dotted path description from the object's root element to the leaf being inspected, it's rather obvious that a tree conversion to a key-value list is comparable to an object to xml mapping. Each element within an XML document has a defined position and can be converted into a path. Therefore I took XStream as a basic and stable conversion tool and replaced the hierarchical driver and writer parts with an own implementation. XStream also comes with a basic path tracking mechanism which - being combined with the other two - strictly leads to a solution being suitable for the task.
With the help of Jackson library, I was able to find all class properties of type String/integer/double, and respective values in a Map class. (without using reflections api!)
TestClass testObject = new TestClass();
com.fasterxml.jackson.databind.ObjectMapper m = new com.fasterxml.jackson.databind.ObjectMapper();
Map<String,Object> props = m.convertValue(testObject, Map.class);
for(Map.Entry<String, Object> entry : props.entrySet()){
if(entry.getValue() instanceof String || entry.getValue() instanceof Integer || entry.getValue() instanceof Double){
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
}
By using Gson,
Convert POJO object to Json
Convert Json to Map
retMap = new Gson().fromJson(new Gson().toJson(object),
new TypeToken<HashMap<String, Object>>() {}.getType()
);
We can use the Jackson library to convert a Java object into a Map easily.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.3</version>
</dependency>
If using in an Android project, you can add jackson in your app's build.gradle as follows:
implementation 'com.fasterxml.jackson.core:jackson-core:2.9.8'
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.9.8'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
Sample Implementation
public class Employee {
private String name;
private int id;
private List<String> skillSet;
// getters setters
}
public class ObjectToMap {
public static void main(String[] args) {
ObjectMapper objectMapper = new ObjectMapper();
Employee emp = new Employee();
emp.setName("XYZ");
emp.setId(1011);
emp.setSkillSet(Arrays.asList("python","java"));
// object -> Map
Map<String, Object> map = objectMapper.convertValue(emp,
Map.class);
System.out.println(map);
}
}
Output:
{name=XYZ, id=1011, skills=[python, java]}
Add Jackson library
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.3</version>
</dependency>
Then you could generate map using Object mapper.
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> map = objectMapper.convertValue(
yourJavaObject,
new TypeReference<Map<String, Object>>() {}
);

Categories

Resources