Guava Predicate Failing To Filter Collection - java

I have the following method to use a Predicate to filter a collection, throwing out any members where propertyName isn't in a given list of allowed values. It uses Common-BeanUtils to extract a value from the object, and that value has to be a String:
public static <T> void filterListByStringPropertyWithAllowableValues(List<T> listToFilter,
final String propertyName,
final List<String> allowedValues) {
Predicate<T> allowedValuesPredicate = new Predicate<T>() {
#Override
public boolean apply(T arg0) {
String value;
boolean result = false;
try {
value = BeanUtils.getProperty(arg0, propertyName);
System.out.println(value);
result = allowedValues.contains(value);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return result;
}
};
Iterables.filter(listToFilter, allowedValuesPredicate);
}
Unfortunately, my test fails utterly.
#Test
public void testfilterListByStringPropertyWithAllowableValues() throws Exception {
TestClass item1 = new TestClass("value1","whatever1");
TestClass item2 = new TestClass("value2","whatever2");
TestClass item3 = new TestClass("value3","whatever3");
List<TestClass> initialList = Lists.newArrayList(item1, item2, item3);
MyCollectionUtils.filterListByStringPropertyWithAllowableValues(initialList, "importantField",
Lists.newArrayList("value1","value2"), 3);
assertTrue("Collection size should be 2. Actual: " + initialList.size(), initialList.size() == 2);
}
Am I making an incredibly stupid mistake here?
Update: working code is below.
public static <T> List<T> filterListByStringPropertyWithAllowableValues(List<T> listToFilter,
final String propertyName,
final Set<String> allowedValues) {
Predicate<T> allowedValuesPredicate = new Predicate<T>() {
#Override
public boolean apply(T arg0) {
String value;
boolean result = false;
try {
value = BeanUtils.getProperty(arg0, propertyName);
System.out.println(value);
result = allowedValues.contains(value);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return result;
}
};
return Lists.newArrayList(Iterables.filter(listToFilter, allowedValuesPredicate));
}

Yes, you're doing an incredibly stupid mistake ;-)
You're not returning the filtered list. filter() doesn't modify the given list. It returns a filtered Iterable.
Also, allowedValues should be a HashSet rather than a List. That would make your filter more efficient. HashSet.contains() runs in constant time, whereas List.contains() is O(n).

Related

Why java streams are not able to handle exception even after surrounding with a try-catch block?

I have the following piece of code with java streams
You can see that I am having an error on the 4th line. Basically the error says Unhandled Exception: AddressException. But you can see that I am catching it within catch block. But still that is not working. Eventhough, if I use a try catch block within the map method it works as shown below
public List<InternetAddress> getListOfInternetEmailAddresses(List<String> toEmails){
List<InternetAddress> internetAddresses = new ArrayList<>();
internetAddresses = toEmails.stream().map(a->{
InternetAddress ia = null;
try{
ia = new InternetAddress(a);
} catch (AddressException e) {
}
return ia;
}).collect(Collectors.toList());
return internetAddresses;
}
Does anyone know why this behaviour and if knows please give some insights to that. One more quetion, does the anonymous inner class will also behave the same ?
Error is shown because you provided method with different signature (additional thows clause). You have to provide implementation that is compatible with java.util.function.Function#apply signature
R apply(T var1);
There is several ways to deal with your problem:
anonymous function with try-catch
public List<InternetAddress> getListOfInternetEmailAddresses(List<String> toEmails) {
return toEmails.stream().map(new Function<String, InternetAddress>() {
#Override
public InternetAddress apply(String email) {
try {
return new InternetAddress(email);
} catch (AddressException e) {
e.printStackTrace();
}
return null;
}
}).collect(Collectors.toList());
}
try-catch in lambda
public List<InternetAddress> getListOfInternetEmailAddresses(List<String> toEmails) {
return toEmails.stream().map(email -> {
try {
return new InternetAddress(email);
} catch (AddressException e) {
e.printStackTrace();
}
return null;
}).collect(Collectors.toList());
}
extracted handling method
public List<InternetAddress> getListOfInternetEmailAddresses(List<String> toEmails) {
return toEmails.stream().map(this::createInternetAddress).collect(Collectors.toList());
}
private InternetAddress createInternetAddress(String email) {
try {
return new InternetAddress(email);
} catch (AddressException e) {
e.printStackTrace();
}
return null;
}
generalized extracted handling method
#FunctionalInterface
public interface FunctionThrowing <T, R, E extends Exception> {
R apply(T var1) throws E;
static <T, R, E extends Exception> Function<T, R> handled(FunctionThrowing<T, R, E> ft) {
return result -> {
try {
return ft.apply(result);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
}
public List<InternetAddress> getListOfInternetEmailAddresses(List<String> toEmails) {
List<InternetAddress> internetAddresses = new ArrayList<>();
internetAddresses = toEmails.stream().map(FunctionThrowing.handled(InternetAddress::new)).collect(Collectors.toList());
return internetAddresses;
}

Return a variable from inside a lambda

I have a method that receives a dto in which many of its fields are used to make a dynamic query based on the non-null fields.
I am accessing each field by reflection in a lambda to add the non-null fields to the dynamic query. This works, but I don't know how to get that list to return it.
#Override
public List<AirlinePreOrderDto> getPreorders(AirlinePreOrderDto airlinePreOrderDto) {
PreOrder entity = PreOrderMapper.mapToJpaEntity(airlinePreOrderDto);
Query dynamicQuery = new Query();
ReflectionUtils.doWithLocalFields(entity.getClass(), field -> {
field.setAccessible(true);
try {
if (field.get(entity) != null) {
if (!field.getName().equals("serialVersionUID")) {
if(field.getName().equals("preorderId")) {
dynamicQuery.addCriteria(Criteria.where(field.getName()).is(field.get(entity)));
} else {
dynamicQuery.addCriteria(Criteria.where(field.getName()).is(field.get(entity)));
}
}
List<AirlinePreOrderDto> result = PreOrderMapper
.mapToDtos(mongoTemplate.find(dynamicQuery, PreOrder.class, "preorders"));
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
});
// return result list;
}
I suggest you to use an enclosing class.
class EnclosingResults {
List<AirlinePreOrderDto> results;
public void setResults(List<AirlinePreOrderDto> results) {
this.results = results;
}
public List<AirlinePreOrderDto> getResults() {
return results;
}
}
So your method will be:
#Override
public List<AirlinePreOrderDto> getPreorders(AirlinePreOrderDto airlinePreOrderDto) {
PreOrder entity = PreOrderMapper.mapToJpaEntity(airlinePreOrderDto);
Query dynamicQuery = new Query();
EnclosingResults resultEncloser = new EnclosingResults();
ReflectionUtils.doWithLocalFields(entity.getClass(), field -> {
field.setAccessible(true);
try {
if (field.get(entity) != null) {
if (!field.getName().equals("serialVersionUID")) {
if(field.getName().equals("preorderId")) {
dynamicQuery.addCriteria(Criteria.where(field.getName()).is(field.get(entity)));
} else {
dynamicQuery.addCriteria(Criteria.where(field.getName()).is(field.get(entity)));
}
}
List<AirlinePreOrderDto> result = PreOrderMapper
.mapToDtos(mongoTemplate.find(dynamicQuery, PreOrder.class, "preorders"));
resultEncloser.setResults(result);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
});
return resultEncloser.getResults()
}
It seems that you don't want to call mongoTemplate.find or PreOrderMapper.mapToDtos inside of the lambda, as the lambda will be executed once for each local field.
But from your code I'd guesstimate that you really want to execute the query after having built the dynamicQuery object from all fields.
And since you already manipulate the object referenced by dynamicQuery inside the lambda, it's as simple as moving the code to actually execute it out of the lambda:
PreOrder entity = PreOrderMapper.mapToJpaEntity(airlinePreOrderDto);
Query dynamicQuery = new Query();
ReflectionUtils.doWithLocalFields(entity.getClass(), field -> {
field.setAccessible(true);
try {
if (field.get(entity) != null) {
if (!field.getName().equals("serialVersionUID")) {
if(field.getName().equals("preorderId")) {
dynamicQuery.addCriteria(Criteria.where(field.getName()).is(field.get(entity)));
} else {
dynamicQuery.addCriteria(Criteria.where(field.getName()).is(field.get(entity)));
}
}
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
});
List<AirlinePreOrderDto> result = PreOrderMapper
.mapToDtos(mongoTemplate.find(dynamicQuery, PreOrder.class, "preorders"));
return result;

Reverse .class to original class type

With the following line of code:
List<Dao<?>> genericList = Dao.get(Person.class, q);
I call the following static method:
/**
* Dynamically create list of generic Dao's
* #param className
* #return
*/
public static List<Dao<?>> get(Class<?> classType, Query q){
List<Dao<?>> list = new ArrayList<>();
try {
List<Map<String, Object>> results = Model.getAll(q);
for (Map<String, Object> map : results) {
Dao<?> obj = PojoFactory.createPojo(classType.getSimpleName());
for (String key : map.keySet()) {
//Double check if field names exist before setting them
//http://commons.apache.org/proper/commons-beanutils/
BeanUtils.setProperty(obj, key, map.get(key));
}
list.add(obj);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return list;
}
Instead of returning a DAO type, I would like to return the correct type so that I don't need to cast afterwards.
In order to do so, I need to be able to reverse:
Person.class
to adapt this line:
List<Dao<?>> genericList = Dao.get(Person.class, q);
to the correct type so that I can call it like this:
List<Person> genericList = Dao.get(Person.class, q);
Any idea?
You should introduce a type parameter in the method header.
public static <T extends Dao<T>> List<T> get(Class<T> classType, Query q){
List<T> list = new ArrayList<>();
try {
List<Map<String, Object>> results = Model.getAll(q);
for (Map<String, Object> map : results) {
T obj = (T) PojoFactory.createPojo(classType.getSimpleName());
for (String key : map.keySet()) {
//Double check if field names exist before setting them
//http://commons.apache.org/proper/commons-beanutils/
BeanUtils.setProperty(obj, key, map.get(key));
}
list.add(obj);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return list;
}
I was assuming that the definition of Person looks like:
class Person extends Dao<Person> {
}

MVEL executeExpression function cannot be concurrent

Run the main function in File2 , the problem is : threads stuck at "rval=MVEL.executeExpression(compiledExpression, vars);" , 10 threads run in sequential order, not parallel , I wanna know why this happened.
PS: I'm using MVEL 2.2 , the latest version
File1:MVELHelper.java
public class MVELHelper {
private static ParserContext _ctx = new ParserContext(false);
//public static Object execute(String expression, Map<String, Object> vars, Databus databus) throws Exception {
public static Object execute(String expression, Map<String, Object> vars) throws Exception {
Object rval = null;
try {
if(vars == null) {
rval = MVEL.eval(expression, new HashMap<String,Object>());
}
else {
rval = MVEL.eval(expression, vars);
}
return rval;
}
catch(Exception e) {
throw new Exception("MVEL FAILED:"+expression,e);
}
}
public static Serializable compile(String text, ParserContext ctx)
throws Exception {
if(ctx == null) {
//ctx = _ctx;
ctx=new ParserContext(false);
}
Serializable exp = null;
try {
exp = MVEL.compileExpression(text, ctx);
//exp = MVEL.compileExpression(text);
}
catch (Exception e) {
throw new Exception("failed to compile expression.", e);
}
return exp;
}
public static Object compileAndExecute(String expression, Map<String, Object> vars) throws Exception {
Object rval = null;
try {
Serializable compiledExpression=compile(expression,null);
System.out.println("[COMPILE OVER, Thread Id="+Thread.currentThread().getId()+"] ");
if(vars == null) {
rval=MVEL.executeExpression(compiledExpression, new HashMap<String,Object>());
//rval = MVEL.eval(exp, new HashMap<String,Object>());
}
else {
//rval=MVEL.executeExpression(compiledExpression, vars,(VariableResolverFactory)null);
rval=MVEL.executeExpression(compiledExpression, vars);
//rval = MVEL.eval(expression, vars);
}
return rval;
}
catch(Exception e) {
throw new Exception("MVEL FAILED:"+expression,e);
}
}
}
File2:ExecThread3.java
public class ExecThread3 implements Runnable{
Map dataMap=null;
public Map getDataMap() {
return dataMap;
}
public void setDataMap(Map dataMap) {
this.dataMap = dataMap;
}
#Override
public void run() {
Map varsMap = new HashMap();
Map dataMap=new HashMap();
dataMap.put("count",100);
varsMap.put("dataMap", dataMap);
String expression="System.out.println(\"[BEFORE Thread Id=\"+Thread.currentThread().getId()+\"] \"+dataMap.get(\"count\"));"+
"Thread.sleep(3000);"+
"System.err.println(\"[AFTER Thread Id=\"+Thread.currentThread().getId()+\"] \"+dataMap.get(\"count\"));";
try {
//MVEL.compileExpression(expression);
MVELHelper.compileAndExecute(expression, varsMap);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
for(int k=0;k<10;k++){
ExecThread3 execThread=new ExecThread3();
new Thread(execThread).start();
}
}
}

converting Object returned by Field.get() to String[] in java reflection

I have a generic class which maintains an internal array(say data) and number of elements(say N) in the array (both private).I can add elements to the array ,which will update the value of N.The public API of the class doesn't have get methods for the data array or N.Still I would like to write unit tests for checking the state of array and N.
public class InternalArray<T> {
private T[] data;
private int N;
private int head;
public InternalArray() {
super();
data = (T[]) new Object[10];
N = 0;
head = 0;
}
public void add(T item){
data[head]=item;
head++;
N++;
}
public T get(){
T item = data[--head];
N--;
return item;
}
}
Here, all I can test are the public APIs .. But I need to test the internal state of the private variables . I thought I would be able to access the fields using reflection.I tried the below code, I can get the value of N. When it comes to T[] data ,I can't figure out how to convert the resulting Object to a String[] ( from call arrayf.get(inst) )
public static void demoReflect(){
try {
Class t = Class.forName("InternalArray");
System.out.println("got class="+t.getName());
InternalArray<String> inst = (InternalArray<String>) t.newInstance();
System.out.println("got instance="+inst.toString());
inst.add("A");
inst.add("B");
Field arrayf = t.getDeclaredField("data");
arrayf.setAccessible(true);
Field nf = t.getDeclaredField("N");
nf.setAccessible(true);
System.out.println("got arrayfield="+arrayf.getName());
System.out.println("got int field="+nf.getName());
int nval = nf.getInt(inst);
System.out.println("value of N="+nval);
Object exp = arrayf.get(inst);
//how to convert this to String[] to compare if this is {"A","B"}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
This gave the output below
got class=InternalArray
got instance=InternalArray#c2ea3f
got arrayfield=data
got int field=N
value of N=2
The Object that you get from the call of arrayf.get(inst) is of type Object[], not String[], because Java generics are implemented through type erasure. You can do this:
Object[] strings = (Object[])arrayf.get(inst);
System.out.println(strings.length);
for (int i = 0 ; i != strings.length ; i++) {
String s = (String)strings[i];
...
}
P.S. I am going to stay away from the discussion on whether it's a good idea to unit test the private details of the implementation.

Categories