I know, I can do several things in JEXL, but unable to find Filter feature in it, which is indeed very useful.
How can I do something like
var x=[{a:11,b=5},{a:1,b=15},{a:12,b=25},{a:4,b=35},{a:7,b=45}];
return x[.a>10].b; // Which filters to {a:11,b=5} & {a:12,b=25}
// & hence returns [5,25]
First of all your syntax is not valid JEXL. I assume you meant this:
var x = [{'a':11,'b':5}, {'a':1,'b':15}, {'a':12,'b':25}, {'a':4,'b':35}, {'a':7,'b':45}];
Since you can call any Java method on any object in a JEXL script, you have (at least theoretically) full access to the Java Stream API.
However, the Stream API isn't directly available from a raw array and we can't just call Arrays.stream(x); without some effort. The easiest way around this is to create a set instead:
var x = {{'a':11,'b':5}, {'a':1,'b':15}, {'a':12,'b':25}, {'a':4,'b':35}, {'a':7,'b':45}};
Now we can simply call stream() and work from there:
x.stream();
What we want now is something like this:
x.stream().filter(function(m){m['a']>10});
Unfortunately the method resolver in JEXL will not be able to correctly resolve Stream.filter(Predicate) with a JEXL function, as it doesn't know how to turn a JEXL function into a Predicate. A JEXL function is of type org.apache.commons.jexl3.internal.Closure.
Thus the very least you need to do is to provide your own Predicate implementation in Java and then create a new instance in your script:
public class MyCustomFilterPredicate implements Predicate<HashMap<String, Integer>> {
#Override
public boolean test(final HashMap<String, Integer> m)
{
return m.get("a") > 10;
}
}
You can then create a new instance in your JEXL script:
var filterPredicate = new('my.custom.filter.predicate.MyCustomFilterPredicate');
The same goes for Stream.map(Function):
public class MyCustomMapFunction implements Function<HashMap<String, Integer>, Integer> {
#Override
public Integer apply(final HashMap<String, Integer> m)
{
return m.get("b");
}
}
And again create a new instance in your script:
var mapFunction = new('my.custom.map.function.MyCustomMapFunction');
Your entire script will then look like this:
var x = {{'a':11,'b':5}, {'a':1,'b':15}, {'a':12,'b':25}, {'a':4,'b':35}, {'a':7,'b':45}};
var filterPredicate = new('my.custom.filter.predicate.MyCustomFilterPredicate');
var mapFunction = new('my.custom.map.function.MyCustomMapFunction');
return x.stream().filter(filterPredicate).map(mapFunction).toArray();
Of course you might have noticed that the reusability of your predicate and function implementations are rather limited. This is why I'd recommend creating implementations that wrap a JEXL Closure:
public class MyCustomFilterPredicate implements Predicate<Object> {
private final Closure closure;
public MyCustomFilterPredicate(final Closure closure) {
this.closure = closure;
}
#Override
public boolean test(final Object o)
{
return (boolean) closure.execute(JexlEngine.getThreadContext(), o);
}
}
public class MyCustomMapFunction implements Function<Object, Object> {
private final Closure closure;
public MyCustomMapFunction(final Closure closure) {
this.closure = closure;
}
#Override
public Object apply(final Object o)
{
return closure.execute(JexlEngine.getThreadContext(), o);
}
}
Now you can change your script as follows and reuse these Java classes in various ways:
var x = {{'a':11,'b':5}, {'a':1,'b':15}, {'a':12,'b':25}, {'a':4,'b':35}, {'a':7,'b':45}};
var filterPredicate = new('my.custom.filter.predicate.MyCustomFilterPredicate', function(m){m['a']>10});
var mapFunction = new('my.custom.map.function.MyCustomMapFunction', function(m){m['b']});
return x.stream().filter(filterPredicate).map(mapFunction).toArray();
Related
I have the following classes
public class MyCustomFactory extends SomeOther3rdPartyFactory {
// Return our custom behaviour for the 'string' type
#Override
public StringType stringType() {
return new MyCustomStringType();
}
// Return our custom behaviour for the 'int' type
#Override
public IntType intType() {
return new MyCustomIntType();
}
// same for boolean, array, object etc
}
Now, for example, the custom type classes:
public class MyCustomStringType extends StringType {
#Override
public void enrichWithProperty(final SomePropertyObject prop) {
super.enrichWithProperty(prop);
if (prop.getSomeAttribute("attribute01")) {
this.doSomething();
this.doSomethingElse();
}
if (prop.getSomeAttribute("attribute02")) {
this.doSomethingYetAgain();
}
// other properties and actions
}
}
But each custom type class like the string one above might have exactly the same if (prop.getSomeAttribute("blah")) { // same thing; }
Suppose I was to add another attribute, is there a nice way I can avoid having to duplicate if statements in each custom type class that needs it? I can move each if statement to utility class but I still need to add the call to the method in the utility class. I think we can do better.
You can create Map<String, Consumer<MyCustomStringType>>, where the key is your attribute name and value is the method call.
public class MyCustomStringType extends StringType {
private final Map<String, Cosnumer<MyCustomStringType>> map = new HashMap<>();
{
map.put("attribute01", o -> {o.doSomething(); o.doSomethingElse();});
map.put("attribute02", MyCustomStringType::doSomethingYetAgain);
// other properties and actions
}
#Override
public void enrichWithProperty(final SomePropertyObject prop) {
super.enrichWithProperty(prop);
map.entrySet().stream()
.filter(entry -> prop.getSomeAttribute(entry.getKey()))
.forEach(entry -> entry.getValue().accept(MyCustomStringType.this));
}
}
Depending on how you initialise this class (and whether this map is always the same), you might be able to turn in into static final immutable map.
I would also recommend naming it better, but a lot here depends on your domain and what this map and loop actually do.
Using GraphStage is recommended in Akka Streams, but I could not find any documentation on using the getStageActor() method in Java (all of the documentation that I have found used Scala).
How can I convert the following code to Java?
lazy val self: StageActor = getStageActor(onMessage)
and
private def onMessage(x: (ActorRef, Any)): Unit =
{
x match {
case (_, msg: String) =>
log.info("received msg, queueing: {} ", msg)
messages = messages.enqueue(msg)
pump()
}
}
According to the getStageActor method documentation, it accepts a value of type
scala.Function1<scala.Tuple2<ActorRef,java.lang.Object>, scala.runtime.BoxedUnit>
which in Scala looks like
((ActorRef, AnyRef)) => Unit
In Java this type would be semantically equivalent (using the Function interface) to
Function<Tuple<ActorRef, Object>, Void>
where Tuple<A, B> is a class which contains two values of types A and B.
Therefore, to call the getStageActor method, you need to create a value of the aforementioned type. You can do it directly by constructing an instance of a class extending AbstractFunction1:
import scala.Function1;
import scala.Tuple2;
import scala.runtime.AbstractFunction1;
import scala.runtime.BoxedUnit;
getStateActor(new AbstractFunction1<Tuple2<ActorRef, Object>, BoxedUnit>() {
#Override
public BoxedUnit apply(Tuple2<ActorRef, Object> args) {
return BoxedUnit.UNIT;
}
});
If you use Java 8, there are syntactically nicer ways to do it using lambda expressions.
If you use Scala 2.12+, then scala.Function1 is a functional interface, and you can use lambda expressions directly:
getStateActor((args: Tuple2<ActorRef, Object>) -> BoxedUnit.UNIT);
If you use an older version of Scala, then due to the way traits are compiled, Function1 is not a functional interface, and you will need to use the scala-java8-compat library. With it, the code looks like
import static scala.compat.java8.JFunction.*;
getStateActor(func((args: Tuple2<ActorRef, Object>) -> BoxedUnit.UNIT));
Then, to implement the logic of the function, you can access elements of the tuple using the _1() and _2() methods:
(args: Tuple2<ActorRef, Object>) -> {
Object msg = args._2();
if (msg instanceof String) {
log.info("received msg, queueing: {} ", msg);
messages = messages.enqueue((String) msg);
pump();
}
return BoxedUnit.UNIT;
}
This is a direct translation of the logic that you wanted to convert.
I have not used getStageActor() before, hence can't provide much help there. As to code conversion from Scala to Java in general, if requirement allows, package a jar containing the classes of the Scala version for the Java app to use; otherwise consider using a Java decompiler (e.g. cfr, procyon) to decompile your Scala-compiled classes and refine the decompiled Java code as needed.
For example decompiling the following dummy Scala code would help reveal a skeletal Java way of lazy val and pattern matching:
class Foo {
lazy val self = dummy(bar(_: String))
def dummy(u: Unit) = 1
private def bar(x: String): Unit = {
x match {
case "blah" => println(s"x = $x")
}
}
}
As shown in the decompiled code below, lazy val is done in Java with the value wrapped inside a synchronized block with a bitmap$0 boolean flag, and pattern matching gets converted to if and MatchError exception:
$ java -jar /path/to/decompiler/cfr_0_125.jar Foo.class
private int self;
private volatile boolean bitmap$0;
private int self$lzycompute() {
Foo foo = this;
synchronized (foo) {
if (!this.bitmap$0) {
new Serializable(this){
public static final long serialVersionUID = 0L;
private final /* synthetic */ Foo $outer;
public final void apply(String x$1) {
this.$outer.Foo$$bar(x$1);
}
{
if ($outer == null) {
throw null;
}
this.$outer = $outer;
}
};
this.self = this.dummy(BoxedUnit.UNIT);
this.bitmap$0 = true;
}
return this.self;
}
}
public int self() {
return this.bitmap$0 ? this.self : this.self$lzycompute();
}
public int dummy(BoxedUnit u) {
return 1;
}
public void Foo$$bar(String x) {
String string = x;
if ("blah".equals(string)) {
Predef$.MODULE$.println((Object)new StringContext(
(Seq)Predef$.MODULE$.wrapRefArray((Object[])new String[]{"x = ", ""})
).s((Seq)Predef$.MODULE$.genericWrapArray((Object)new Object[]{x}))
);
BoxedUnit boxedUnit = BoxedUnit.UNIT;
return;
}
throw new MatchError((Object)string);
}
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));
Is there a way to check if all objects in a list have the same attribute with Google Guava API?
Moreover, is there a way to send more parameters to Predicate?
Let's said I want to filter all my objects with string that I am getting from the user,
and I want the Predicate to use this parameter when applying the filter.
You can create your own predicate as follows:
class MyPredicate implements Predicate<MyObject> {
private final String parameter;
public MyPredicate(String parameter) {this.parameter = parameter;}
boolean apply(MyObject input) {
// apply predicate using parameter.
}
}
You can then filter by doing:
Iterables.filter(myIterable, new MyPredicate(myParameter));
You should be wary though that this performs a lazy filter.
Is there a way to check if all objects in a list have the same attribute with Google Guava API?
Yes:
Foo first = list.get(0).getFoo();
boolean allSameFoo = Iterables.all(list, element -> element.getFoo().equals(first));
Or, if you're not using Java 8 yet:
final Foo first = list.get(0).getFoo();
boolean allSameFoo = Iterables.all(list, new Predicate<Bar> {
#Override
public boolean apply(Bar element) {
return element.getFoo().equals(first);
}
});
is there a way to send more parameters to Predicate
Yes:
String s = getFromUser();
Iterables.filter(list, element -> element.getFoo().equals(s));
Or, if you're not using Java 8 yet:
final String s = getFromUser();
Iterables.filter(list, new Predicate<Bar> {
#Override
public boolean apply(Bar element) {
return element.getFoo().equals(s);
}
});
It seems you don't really know how inner classes work, so you should read the tutorial about them: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html.
I am using Flex 3 and make a call through a RemoteObject to a Java 1.6 method and exposed with BlazeDS and Spring 2.5.5 Integration over a SecureAMFChannel. The ActionScript is as follows (this code is an example of the real thing which is on a separate dev network);
import com.adobe.cairngorm.business.ServiceLocator;
import mx.collections.ArrayCollection;
import mx.rpc.remoting.RemoteObject;
import mx.rpc.IResponder;
public class MyClass implements IResponder
{
private var service:RemoteObject = ServiceLocator.getInstance().getRemoteOjbect("mySerivce");
public MyClass()
{
[ArrayElementType("Number")]
private var myArray:ArrayCollection;
var id1:Number = 1;
var id2:Number = 2;
var id3:Number = 3;
myArray = new ArrayCollection([id1, id2, id3]);
getData(myArray);
}
public function getData(myArrayParam:ArrayCollection):void
{
var token:AsyncToken = service.getData(myArrayParam);
token.addResponder(this.responder); //Assume responder implementation method exists and works
}
}
This will make a call, once created to the service Java class which is exposed through BlazeDS (assume the mechanics work because they do for all other calls not involving Collection parameters). My Java service class looks like this;
public class MySerivce {
public Collection<DataObjectPOJO> getData(Collection<Long> myArrayParam) {
//The following line is never executed and throws an exception
for (Long l : myArrayParam) {
System.out.println(l);
}
}
}
The exception that is thrown is a ClassCastException saying that a java.lang.Integer cannot be cast to a java.lang.Long. I worked around this issue by looping through the collection using Object instead, checking to see if it is an Integer, cast it to one, then do a .longValue() on it then add it to a temp ArraList. Yuk.
The big problem is my application is supposed to handle records in the billions from a DB and the id will overflow the 2.147 billion limit of an integer. I would love to have BlazeDS or the JavaAdapter in it, translate the ActionScript Number to a Long as specified in the method. I hate that even though I use the generic the underlying element type of the collection is an Integer. If this was straight Java, it wouldn't compile.
Any ideas are appreciated. Solutions are even better! :)
Please read the following threads related to your issue. You can find there some workarounds.
https://bugs.adobe.com/jira/browse/BLZ-115
https://bugs.adobe.com/jira/browse/BLZ-305
You can also change the argument on the Java side to expect a Long[] rather than a Collection<Long>. Because the native Java array is strongly typed, it deserializes correctly.
Flex serializes an ArrayCollection of Numbers to an ArrayCollection<Integer> in Java.
Since Adobe's ArrayCollection extends ArrayList, you can run the Collection through the following function. This should produce a List of Long values.
public class TransformUtils {
public static final <T extends Number> List<Long> toLongList(Collection<T> values) {
List<Long> list = new ArrayList();
for (T value : values) {
list.add(value.longValue());
}
return list;
}
}
public class MySerivce {
public Collection<DataObjectPOJO> getData(Collection<Long> myArrayParam) {
myArrayParam = TransformUtils.toLongList(myArrayParam);
for (Long l : myArrayParam) {
System.out.println(l);
}
}
}
Guava :)
public static final <T extends Number> List<Long> toLongList(Collection<T> values) {
return Lists.newArrayList(new Function<T, Long>() {
#Override public Long apply(T value) {
return value.longValue(); }));}