Java - JxPath - Spring
I have List<MyClass> myClassList filled with MyClass objects. I am trying to find a cleanest and fastest way to get Set<String> a property out of myClassList.
class MyClass{
private String a;
private String b;
// setters getters
}
I am using jxpath for searching but I am not sure it can also do what I mentioned above.
JXPathContext ctx = JXPathContext.newContext(myClassList);
Iterate<String> aProps = ctx.iterate("? what to write");
Can you help?
instead of Jxpath there is way doing it in Guava library.
here is the implementation
public static final Function<Obj, String> FOO = new Function<Obj, String>() {
public String apply(Obj input) {
return input.foo;
}
};
List<String> fooList = Lists.transoform(targetList, Object.FOO)
or
List<String> fooList = Collections2.transoform(targetList, Object.FOO)
Related
I have one specific case. I need to serialize/deserialize an object to Map<String, Object>. I have a class that looks like the following:
public class Data {
public String name;
public Map<String, Object> options = new HashMap<>();
}
I can put to this options objects of any type. For instance:
public class Option {
public int id;
...
}
public class TestOpt {
public name;
...
}
and I try to serialize and deserialize it:
public static void main(String... args) {
ObjectMapper mapper = new ObjectMapper();
Option o = new Option();
o.id = 1;
TestOpt t = new TestOpt();
t.name = "fff";
Data data = new Data();
data.name = "data";
data.options.put("o", o);
data.options.put("t", t);
String json = mapper.writeValueAsString(data);
Data d1 = mapper.readValue(json, Data.class);
// I get error because options.get("o") contains LinkedHashMap instead of Option.class
System.out.println(((Option)d1.options.get("o")).id);
}
How can I fix this issue?
The value of the serialized json is
{"name":"data","options":{"t":{"name":"fff"},"o":{"id":1}}}
So, the problem is that the object mapper has no way to tell that the o value inside the json is an Option. The best guess is that it could be a map and thus it is deserialized as a LinkedHashMap.
If you are sure that the element o is an Option, you can convert the value using an object mapper:
Option option = mapper.convertValue(d1.options.get("o"), Option.class);
But please note, that this means that the value is again serialized and then deserialized using the right type information. You can do that, but it is not a good solution.
If it is possible, a better way would be to change your model from a generic map to a specific class that contains the type information:
class Data {
public String name;
public DataOptions options = new DataOptions();
}
class DataOptions {
public Option o;
public TestOpt t;
}
Serializing this model has the same json representation as the model using a map, and the model can be used to deserialize the json from your example.
I would like to use functional programming to copy data from a collection of one object to a collection of other objects.
I have been reading several Java 8 books and researching online. I am pretty sure I want to use stream(), but just about every example I have seen always iterates through a collection, does some processing on the objects in the collection, and uses println() to output the contents. No one seems to discuss how to deal with situations like the one described below.
Suppose we have the following objects:
public class ObjectA
{
private String someData;
private int moreData;
public String getSomeData()
{
return someData;
}
public void setSomeData(String sData)
{
someData = sData;
}
public int getMoreData()
{
return moreData;
}
public void setMoreData(int mData)
{
moreData = mData;
}
}
public class ObjectB
{
private String b_Data;
public String getB_Data()
{
return b_Data;
}
public void setB_Data(String bData)
{
b_Data = bData;
}
}
I want to create a collection of ObjectB objects whose b_data atributes are equal to the someData attributes in a collection of ObjectAs.
A reasonably good way to do this is illustrated in the code below:
public class Collector
{
public Collection<ObjectB> collectObjects(Collection<ObjectA> theAs)
{
// The use of an ArrayList is arbitrary. I might want to use any number
// of different lists or even different collections!
final Collection<ObjectB> theBs = new ArrayList<ObjectB>();
for(ObjectA obj : theAs)
{
final ObjectB bobj = new ObjectB();
bobj.setB_Data(obj.getSomeData());
theBs.add(bobj);
}
return theBs;
}
}
The code in the collectObjects() method will work, but it uses techniqhes of imperative programming. I would like to know how to make the collection of ObjectBs using functional techniques.
Is there a way to accomplish this using streams and lambdas?
This situation actually applies perfectly with the Stream API. What you want is to:
Make a Stream<ObjectA> which is a Stream of your input list, with theAs.stream().
Map each ObjectA in the Stream to an ObjectB with Stream.map.
Collect the result with Stream.collect into a new list using Collectors.toList().
This would be an implementation:
public Collection<ObjectB> collectObjects(Collection<ObjectA> theAs) {
return theAs.stream().map(obj -> {
final ObjectB bobj = new ObjectB();
bobj.setB_Data(obj.getSomeData());
return bobj;
}).collect(Collectors.toList());
}
Of course, you could create a constructor of ObjectB that takes obj.getSomeData() as parameter. It would simplify the code because then you could write:
public Collection<ObjectB> collectObjects(Collection<ObjectA> theAs) {
return theAs.stream().map(obj -> new ObjectB(obj.getSomeData())).collect(Collectors.toList());
}
obj -> new ObjectB(obj.getSomeData()) is called a lambda expression.
You can do it like this:
List<ObjectB> theBs = theAs
.stream()
.map(a-> {
final ObjectB bobj = new ObjectB();
bobj.setB_Data(a.getSomeData());
return bobj;
}).collect(Collectors.toList());
The a -> { ... } construct is a lambda, a construct that lets you pass some executable code into a method call.
The body of the lambda comes straight from the loop body in your second example.
I have a map with keys and string values.
This Map has been built reading a resource bundle where the data is organised in the following way:
height=160
weight=80
name=bob
And I have a class Person which has the fields: height, weight and name.
class Person{
int height;
int weight;
String name;
//..getter and setter..
}
I would like to create an instance of the class Person from the Map: height:160, weight:80, name:bob
The best would be a generic solution, or something that uses some utilities.
Do you have any idea? how can I do that in Java? or using the framework Spring?
Have a look at the Spring BeanWrapper interface and its implementations if you'd like to use something from Spring. You can use it to wrap your bean and dynamically populate your bean from a map like this:
Map<String, String> properties = new HashMap<>();
properties.put("height", "160");
properties.put("weight", "80");
properties.put("name", "bob");
BeanWrapper person = new BeanWrapperImpl(new Person());
for (Map.Entry<String, String> property : properties.entrySet()) {
person.setPropertyValue(property.getKey(), property.getValue());
}
System.out.println(person.getWrappedInstance().toString());
This will print:
-> Person [height=160, weight=80, name=bob]
The easiest way to achieve this is to use jackson's ObjectMapper class.
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> fields = ...;
Person o = mapper.convertValue (fields, Person.class);
The classic Java way is to pass the value Map as an argument to the constructor of Person and let person read the properties from the map.
This way you can have multiple ways for constructing a Person object. Either by passing arguments directly, or passing the map.
I would like to bring forward another benefit of this approach. If you do it this way, the cohesion is very high. This means that the knowledge of how to construct a Person object from a Map of values is coded within the class itself. If you would do this outside of the class and you want to construct Person objects in different locations of you program, then you would need to replicate the code for getting values from the map or abstract it into a utility method. Now you don't, and if you every would need to change the way how to construct a Person object you simply change it in one place.
import java.util.Map;
public class Person {
private static final String WEIGHT_PROPERTY = "weight";
private static final String HEIGHT_PROPERTY = "height";
private final int height;
private final int weight;
public Person(Map<String, String> map){
height = Integer.parseInt(map.get(HEIGHT_PROPERTY));
weight = Integer.parseInt(map.get(WEIGHT_PROPERTY));
}
public int getHeight() {
return height;
}
public int getWeight() {
return weight;
}
}
Map<String, String> map = ...;
int height = Integer.parseInt(map.get("height"));
int weight = Integer.parseInt(map.get("weight"));
Person p = new Person(height, weight);
Note that ResourceBundle is normally used to deal with internationalization. If you just need to read properties, then use the java.util.Properties class.
Simplifying #Jeroen Peeters post
public class Person {
Map<String, String> prop;
public Person(Map<String, String> map){
prop = map
}
public int getHeight() {
return Integer.parseInt(prop.get("height"))
}
public int getWeight() {
return Integer.parseInt(prop.get("weight"));
}
}
I have an ArrayList of objects, which I need to sort using two attributes (using Comparators). I need to save the sorted output to a text file with a different name, depending on the attribute used to sort. For example, if the list is sorted by attribute1 then file will be attribute1.txt, if attribute2 the file will be attribute2.txt.
How I want it to work (pseudocode):
if(sortedByAtr1){
FileWriter fwstream = new FileWriter(sortedByAtribute1.getName()+".txt");
}
else(sortedByAtr2){
FileWriter fwstream = new FileWriter(sortedByAtribute2.getName()+".txt");
}
Is this possible?
I appreciate any advice.
Thanks.
Servo
Here's an object-oriented approach to solving this requirement.
Use a wrapper for the List and its sorting attribute:
public class ListSorter<V> {
private final List<V> values;
private String sortingAttribute;
public ListSorter(List<V> values) {
this.values = values;
}
public void sort(AttributeComparator<V> comparator) {
Collections.sort(values, comparator);
sortingAttribute = comparator.getSortingAttribute();
}
public String getSortingAttribute() {
return sortingAttribute;
}
}
Extend the Comparator interface so you can get your attribute name:
public interface AttributeComparator<T> extends Comparator<T> {
public String getSortingAttribute();
}
Create custom AttributeComparators like this:
public class FooBarComparator implements AttributeComparator<Foo> {
public int compare(Foo foo1, Foo foo2) {
// skipped nullchecks for brevity
return foo1.getBar().compare(foo2.getBar());
}
public String getSortingAttribute() {
return "bar";
}
}
Use:
List<Foo> yourList = new ArrayList<Foo>();
ListSorter<Foo> example = new ListSorter<Foo>(yourList);
AttributeComparator comparator1 = new FooBarComparator();
example.sort(comparator1);
FileWriter fwstream = new FileWriter(example.getSortingAttribute() +".txt");
I have the ViewValue class defined as follows:
class ViewValue {
private Long id;
private Integer value;
private String description;
private View view;
private Double defaultFeeRate;
// getters and setters for all properties
}
Somewhere in my code i need to convert a list of ViewValue instances to a list containing values of id fields from corresponding ViewValue.
I do it using foreach loop:
List<Long> toIdsList(List<ViewValue> viewValues) {
List<Long> ids = new ArrayList<Long>();
for (ViewValue viewValue : viewValues) {
ids.add(viewValue.getId());
}
return ids;
}
Is there a better approach to this problem?
We can do it in a single line of code using java 8
List<Long> ids = viewValues.stream().map(ViewValue::getId).collect(Collectors.toList());
For more info : Java 8 - Streams
You could do it in a one-liner using Commons BeanUtils and Collections:
(why write your own code when others have done it for you?)
import org.apache.commons.beanutils.BeanToPropertyValueTransformer;
import org.apache.commons.collections.CollectionUtils;
...
List<Long> ids = (List<Long>) CollectionUtils.collect(viewValues,
new BeanToPropertyValueTransformer("id"));
Use google collections. Example:
Function<ViewValue, Long> transform = new Function<ViewValue, Long>() {
#Override
public Long apply(ViewValue from) {
return from.getId();
}
};
List<ViewValue> list = Lists.newArrayList();
List<Long> idsList = Lists.transform(list, transform);
UPDATE:
On Java 8 you don't need Guava. You can:
import com.example.ViewValue;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
Function<ViewValue, Long> transform = ViewValue::getId;
List<ViewValue> source = new ArrayList<>();
List<Long> result = source.stream().map(transform).collect(Collectors.toList());
Or just:
List<ViewValue> source= new ArrayList<>();
List<Long> result = source.stream().map(ViewValue::getId).collect(Collectors.toList());
NEXT UPDATE (The last one after Javaslang to Vavr name change):
Currently it's worth to mention about the solution with Javaslang library(http://www.javaslang.io/) Vavr library (http://www.vavr.io/). Let's assume that we have our list with genuine objects:
List<ViewValue> source = newArrayList(new ViewValue(1), new ViewValue(2), new ViewValue(2));
We could make transformation with List class from Javaslang library (on the long run the collect is not convenient):
List<Long> result = io.vavr.collection.List.ofAll(source).map(ViewValue::getId).toJavaList();
But you will see the power with only the Javaslang lists:
io.vavr.collection.List<ViewValue> source = javaslang.collection.List.of(new ViewValue(1), new ViewValue(2), new ViewValue(3));
io.vavr.collection.List<Long> res = source.map(ViewValue::getId);
I encourage to take a look available collections and new types on that library (I like especially the Try type). You will find the documentation under the following address: http://www.javaslang.io/javaslang-docs/ http://www.vavr.io/vavr-docs/.
PS. Due to the Oracle and the "Java" word within the name they had to change the library name from javaslang to something else. They had decided to Vavr.
EDIT: This answer is based on the idea that you'll need to do similar things for different entities and different properties elsewhere in your code. If you only need to convert the list of ViewValues to a list of Longs by ID, then stick with your original code. If you want a more reusable solution, however, read on...
I would declare an interface for the projection, e.g.
public interface Function<Arg,Result>
{
public Result apply(Arg arg);
}
Then you can write a single generic conversion method:
public <Source, Result> List<Result> convertAll(List<Source> source,
Function<Source, Result> projection)
{
ArrayList<Result> results = new ArrayList<Result>();
for (Source element : source)
{
results.add(projection.apply(element));
}
return results;
}
Then you can define simple projections like this:
private static final Function<ViewValue, Long> ID_PROJECTION =
new Function<ViewValue, Long>()
{
public Long apply(ViewValue x)
{
return x.getId();
}
};
And apply it just like this:
List<Long> ids = convertAll(values, ID_PROJECTION);
(Obviously using K&R bracing and longer lines makes the projection declaration a bit shorter :)
Frankly all of this would be a lot nicer with lambda expressions, but never mind...
I've implemented a small functional library for this usecase. One of the methods has this signature:
<T> List<T> mapToProperty(List<?> objectList, String property, Class<T> returnType)
Which takes the string and uses reflection to create a call to the property then it returns a List backed by the objectList where get and iterator implemented using this property call.
The mapToProperty functions is implemented in terms of a general map function that takes a Function as a mapper though, just as another post described. Very usefull.
I suggest you read up on basic functionl programming and in particular take a look at Functors (objects implementing a map function)
Edit: Reflection really doesn't have to be expensive. The JVM has improved a lot in this area. Just make sure to compile the invocation once and reuse it.
Edit2: Sample code
public class MapExample {
public static interface Function<A,R>
{
public R apply(A b);
}
public static <A,R> Function<A,R> compilePropertyMapper(Class<A> objectType, String property, Class<R> propertyType)
{
try {
final Method m = objectType.getMethod("get" + property.substring(0,1).toUpperCase() + property.substring(1));
if(!propertyType.isAssignableFrom(m.getReturnType()))
throw new IllegalArgumentException(
"Property "+property+" on class "+objectType.getSimpleName()+" is not a "+propertyType.getSimpleName()
);
return new Function<A,R>()
{
#SuppressWarnings("unchecked")
public R apply(A b)
{
try {
return (R)m.invoke(b);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
};
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T1,T2> List<T2> map(final List<T1> list, final Function<T1,T2> mapper)
{
return new AbstractList<T2>()
{
#Override
public T2 get(int index) {
return mapper.apply(list.get(index));
}
#Override
public int size() {
return list.size();
}
};
}
#SuppressWarnings("unchecked")
public static <T1,T2> List<T2> mapToProperty(List<T1> list, String property, Class<T2> propertyType)
{
if(list == null)
return null;
else if(list.isEmpty())
return Collections.emptyList();
return map(list,compilePropertyMapper((Class<T1>)list.get(0).getClass(), property, propertyType));
}
}
You could use a wrapper:
public class IdList impements List<Long>
{
private List<ViewValue> underlying;
pubic IdList(List<ViewValue> underying)
{
this.underlying = underying;
}
public Long get(int index)
{
return underlying.get(index).getId()
}
// other List methods
}
Though that's even more tedious work, it could improve performance.
You could also implement your and my solution generic-ly using reflection, but that would be very bad for performance.
There's no short and easy generic solution in Java, I'm afraid. In Groovy, you would simply use collect(), but I believe that involves reflection as well.
That depends on what you then do with the List<Long>, and the List<ViewValue>
For example you might get sufficient functionality from creating your own List implementation that wraps a List<ViewValue>, implementing iterator() with an iterator implementation that iterates over the ViewValues, returning the id.
You can populate a map from the properties of a list of objects (say id as key and some property as value) as below
Map<String, Integer> mapCount = list.stream().collect(Collectors.toMap(Object::get_id, Object::proprty));