Giter VIP home page Giter VIP logo

jaque's Introduction

Average time to resolve an issue Maven Central

The project is discontinued, but inspired a strong successor.

JAva QUEry

This library enables Java 8 Lambdas to be represented as objects in the form of expression trees at runtime:

void method(Predicate<Customer> p) {
  LambdaExpression<Predicate<Customer>> parsed = LambdaExpression.parse(p);
  //Use parsed Expression Tree...
}

making it possible to create type-safe fluent interfaces, i.e. instead of:

Customer obj = ...
obj.property("name").eq("John")

one can write

method<Customer>(obj -> obj.getName() == "John")

in type-safe, refactoring friendly manner. And then the library developer will be able to parse the produced Lambda to the corresponding Expression Tree for analysis.


For example, JPA Criteria API could benefit a lot from using JaQue, e.g.:

//instead of this:
Root<Pet> pet = cq.from(Pet.class);
Join<Pet, Owner> owner = pet.join(Pet_.owners);

//it could be this:
Join<Pet, Owner> owner = pet.join(Pet::getOwners);

//and instead of this:
query.where(pet.get(Pet_.color).isNull());
query.where(builder.equal(pet.get(Pet_.name), "Fido")
	.and(builder.equal(pet.get(Pet_.color), "brown")));
	
//it could be this:
query.where(pet -> pet.getColor() == null);
query.where(pet -> (pet.getName() == "Fido") && (pet.getColor() == "brown"));

If you are looking for an oportunity to start an open source project, implementing the above should be very beneficial for a very large developer comminuty. Should you start this or any other open source project based on JaQue, I'll be happy to assist you.

How to write fluent interface with JaQue?

  • Suppose you want to reference some class property
public class Fluent<T> {

	// this interface is required to make the lambda Serializable, which removes a need for 
	// jdk.internal.lambda.dumpProxyClasses system property. See below.
	public static interface Property<T, R> extends Function<T, R>, Serializable {
	}

	public Fluent<T> property(Property<T, ?> propertyRef) {
		LambdaExpression<Function<T, ?>> parsed = LambdaExpression
				.parse(propertyRef);
		Expression body = parsed.getBody();
		Expression methodCall = body;
		
		// remove casts
		while (methodCall instanceof UnaryExpression)
			methodCall = ((UnaryExpression) methodCall).getFirst();

		// checks are omitted for brevity
		Member member = ((MemberExpression) ((InvocationExpression) methodCall)
				.getTarget()).getMember();
		
		// use member
		...
		
		return this;
	}
}
  • Now your users will be able to write
Fluent<Customer> f = new Fluent<Customer>();
f.property(Customer::getName);

Make the lambda Serializable, as shown in example above. If the lambda is not serializable, the jdk.internal.lambda.dumpProxyClasses system property must be set and point to an existing writable directory to give the parser access to the lambda byte code.

Resources

jaque's People

Contributors

kostat avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jaque's Issues

Parsing lambda expression with variables does not work

Hi,
I am trying to use Jaque to parse a SerializablePredicate in order to build a MongoDB query.

It works fine like this:
LambdaExpression<SerializablePredicate> ex = LambdaExpression.parse(t -> t.getName() == "Maria Bonita");

Or even like this:
public void testExpression2() {
this.testExpression(t -> t.getName() == "Maria Bonita");
}
protected void testExpression(SerializablePredicate p) {
final LambdaExpression<SerializablePredicate> ex = LambdaExpression.parse(p);
assertNotNull(ex);
}

But if I try to use name as a String variable, it will not work AND try to parse from the file system, throwing a misleading exception;

Attached is a JUnit test file that will show what I mean. Just run the tests.
Ops, turns out I cant attach .java files. The code is bellow:


/**
*
*/
package commons.queries;

import static org.junit.Assert.assertNotNull;

import java.io.Serializable;
import java.util.function.Predicate;

import org.junit.Test;

import com.trigersoft.jaque.expression.LambdaExpression;

/**

  • @author gatto
    */
    public class SerializablePredicateTest {

    @test
    public void testExpression1() {
    final LambdaExpression<SerializablePredicate> ex = LambdaExpression.parse(t -> t.getName() == "Maria Bonita");
    assertNotNull(ex);
    }

    @test
    public void testExpression2() {
    this.testExpression(t -> t.getName() == "Maria Bonita");
    }

    @test
    public void testExpression3() {
    final String name = "Maria Bonita";
    this.testExpression(name);
    }

    @test
    public void testExpression4() {
    this.testExpression("Maria Bonita");
    }

    protected void testExpression(final String name) {
    this.testExpression(t -> t.getName() == name);
    }

    protected void testExpression(SerializablePredicate p) {
    final LambdaExpression<SerializablePredicate> ex = LambdaExpression.parse(p);
    assertNotNull(ex);
    }
    }

interface SerializablePredicate extends Predicate, Serializable {

}

class Person {
private String name;

/**
 * @return the name
 */
public String getName() {
    return this.name;
}

/**
 * @param name the name to set
 */
public void setName(String name) {
    this.name = name;
}

}

Usage and applicability questions

I'd like to use the concept/approach of this library to have remote reactive operations (backed by RxJava/Reactive RPC) and I have the following questions:

  • Does JaQue support non-lambdas, such as anonymous inner classes or actual implementors of a particular functional interface?
  • Lambdas (and inner classes) may capture things that make no sense (or aren't available) on the other side. Is it possible to whitelist what the lambda body/method can do or is safe (such as System.currentTimeMillis())?
  • What would you suggest as the means to get the context information into the expression-tree to be run remotely? For example, instead of sending Function<T, R>, one should send BiFunction<T, C, R> where C is the type of the remotely available context object. This means the fluent API should be designed with the BiFunction as well (or the entire fluent API should carry around the context type C)?

"Numeric" comparison with other objects

I am trying to implement comparisons like "greater than" or "less than" for non-numeric Java objects. For example a LocalDate. I want the LocalDate#isAfter(LocalDate) method to be evaluated as a "greater than" operation. What I tried (simplified version), was this:

LocalDate date1 = LocalDate.of(2016, 8, 23);
LocalDate date2 = LocalDate.now();
Expression.binary(ExpressionType.GreaterThan, Expression.constant(date1), Expression.constant(date2));

What I found was that JaQue throws an IllegalArgumentExceptionin the createNumericComparison method, because java.time.LocalDate is not a numeric value.
Any way I can get this to work?

hello , how to get child class

eg:

================
public class BaseEntity implements Serializable
protected Integer Id;
...
}

public class Foo extends BaseEntity{ ... }

public class Fluent<T>{
  private Class clz; 
  public interface Property<T, R> extends Function<T, R>, Serializable { }
  public Fluent parse(Property<T, ?> propertyRef){
       LambdaExpression<Property<T, ?>> expression = LambdaExpression.parse(propertyRef);
        List<ParameterExpression> params = expression.getParameters();
        this.clz = params.get(0).getResultType();
        System.err.println("clz= "+this.clz);
}
===================
Then Call by:

Fluent<Foo> f = new Fluent<Foo>();
f.parse(Foo::getId)

ending ==> print out : clz = BaseEntity
but, I need to print out " Foo" of class name;
help, How can i do ...
THX !

Parsing of a lambda expression promoting char to int fails in one of two ways

Testing commit 3c1c4ec, built locally. asm version 5.0.3.

This test:

    @Test
    public void canParseAnExpressionWhereCharIsPromotedToIntAsAMethodParameter() throws Exception {
        SerializableFunction<String, Integer> e = s -> Math.abs(s.charAt(0));
        LambdaExpression.parse(e);
    }

Fails like this:

java.lang.ClassCastException: Cannot cast com.trigersoft.jaque.expression.MemberExpression to int
    at java.lang.Class.cast(Class.java:3258)
    at com.trigersoft.jaque.expression.TypeConverter.defaultConvert(TypeConverter.java:65)
    at com.trigersoft.jaque.expression.TypeConverter.defaultConvert(TypeConverter.java:61)
    at com.trigersoft.jaque.expression.TypeConverter.visit(TypeConverter.java:107)
    at com.trigersoft.jaque.expression.TypeConverter.visit(TypeConverter.java:24)
    at com.trigersoft.jaque.expression.MemberExpression.visit(MemberExpression.java:70)
    at com.trigersoft.jaque.expression.Expression.accept(Expression.java:1443)
    at com.trigersoft.jaque.expression.TypeConverter.visit(TypeConverter.java:85)
    at com.trigersoft.jaque.expression.TypeConverter.visit(TypeConverter.java:24)
    at com.trigersoft.jaque.expression.InvocationExpression.visit(InvocationExpression.java:50)
    at com.trigersoft.jaque.expression.Expression.accept(Expression.java:1443)
    at com.trigersoft.jaque.expression.TypeConverter.convert(TypeConverter.java:36)
    at com.trigersoft.jaque.expression.ExpressionMethodVisitor.visitMethodInsn(ExpressionMethodVisitor.java:730)
    at org.objectweb.asm.ClassReader.a(Unknown Source)
    at org.objectweb.asm.ClassReader.b(Unknown Source)
    at org.objectweb.asm.ClassReader.accept(Unknown Source)
    at org.objectweb.asm.ClassReader.accept(Unknown Source)
    at com.trigersoft.jaque.expression.ExpressionClassCracker.parseClass(ExpressionClassCracker.java:177)
    at com.trigersoft.jaque.expression.ExpressionClassCracker.lambda(ExpressionClassCracker.java:81)
    at com.trigersoft.jaque.expression.LambdaExpression.parse(LambdaExpression.java:91)

And this one:

    @Test
    public void canParseAnExpressionWhereCharIsPromotedToIntAsAnOperand() throws Exception {
        SerializableFunction<String, Integer> e = s -> s.charAt(0) + 1;
        LambdaExpression.parse(e);
    }

Fails like this:

java.lang.IllegalArgumentException: char
    at com.trigersoft.jaque.expression.Expression.createNumeric(Expression.java:337)
    at com.trigersoft.jaque.expression.Expression.add(Expression.java:185)
    at com.trigersoft.jaque.expression.ExpressionMethodVisitor.visitInsn(ExpressionMethodVisitor.java:297)
    at org.objectweb.asm.ClassReader.a(Unknown Source)
    at org.objectweb.asm.ClassReader.b(Unknown Source)
    at org.objectweb.asm.ClassReader.accept(Unknown Source)
    at org.objectweb.asm.ClassReader.accept(Unknown Source)
    at com.trigersoft.jaque.expression.ExpressionClassCracker.parseClass(ExpressionClassCracker.java:177)
    at com.trigersoft.jaque.expression.ExpressionClassCracker.lambda(ExpressionClassCracker.java:81)
    at com.trigersoft.jaque.expression.LambdaExpression.parse(LambdaExpression.java:91)

jaque in annotation processor

Hello!

Sorry, that I'm abusing Issues forum.
I'm going to suggest a feature request rather than to report an issue.

Did you think about running jaque as part of annotation processor?
If it's possible then expression tree can be used to generate some code at compile time (e.g. JPA expressions), or what ever other code or resource.

Possible continuation

I saw that this project was discontinued. Is there any chance I can keep using it and keep it up to date myself? My library depends heavily on it and I can't migrate to the successor you've mentioned.

java.lang.RuntimeException: error parsing class file

Can help overcome the following error:

java.lang.RuntimeException: error parsing class file mz/co/ACSystem/MVCTest/controllers/UserController$$Lambda$4.class
com.trigersoft.jaque.expression.ExpressionClassCracker.parseClass(ExpressionClassCracker.java:209)
com.trigersoft.jaque.expression.ExpressionClassCracker.parseClass(ExpressionClassCracker.java:191)
com.trigersoft.jaque.expression.ExpressionClassCracker.parseFromFileSystem(ExpressionClassCracker.java:164)
com.trigersoft.jaque.expression.ExpressionClassCracker.lambda(ExpressionClassCracker.java:122)
com.trigersoft.jaque.expression.LambdaExpression.parse(LambdaExpression.java:91)
mz.co.ACSystem.MVCTest.repository.ConvertLambdaToSql.toSql(ConvertLambdaToSql.java:47)
mz.co.ACSystem.MVCTest.repository.UWork.get(UWork.java:74)
mz.co.ACSystem.MVCTest.controllers.UserController.list(UserController.java:22)
mz.co.ACSystem.MVCTest.controllers.UserController$Proxy$_$$WeldClientProxy.list(Unknown Source)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:497)
net.vidageek.mirror.provider.java.PureJavaMethodReflectionProvider.invoke(PureJavaMethodReflectionProvider.java:38)
net.vidageek.mirror.invoke.MethodHandlerByMethod.withArgs(MethodHandlerByMethod.java:54)
br.com.caelum.vraptor.observer.ExecuteMethod.execute(ExecuteMethod.java:87)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:497)
org.jboss.weld.injection.MethodInjectionPoint.invokeOnInstanceWithSpecialValue(MethodInjectionPoint.java:93)
org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:266)
org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:253)
org.jboss.weld.event.ObserverMethodImpl.notify(ObserverMethodImpl.java:232)
org.jboss.weld.event.ObserverNotifier.notifyObserver(ObserverNotifier.java:169)
org.jboss.weld.event.ObserverNotifier.notifyObserver(ObserverNotifier.java:165)
org.jboss.weld.event.ObserverNotifier.notifyObservers(ObserverNotifier.java:119)
org.jboss.weld.event.ObserverNotifier.fireEvent(ObserverNotifier.java:112)
org.jboss.weld.event.EventImpl.fire(EventImpl.java:83)
br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:78)
br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:98)
br.com.caelum.vraptor.interceptor.FlashInterceptor$Proxy$
$$WeldClientProxy.intercept(Unknown Source)
br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:58)
br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:83)
br.com.caelum.vraptor.core.DefaultInterceptorStack$Proxy$
$$WeldClientProxy.next(Unknown Source)
br.com.caelum.vraptor.interceptor.DefaultSimpleInterceptorStack.next(DefaultSimpleInterceptorStack.java:49)
br.com.caelum.vraptor.interceptor.DefaultSimpleInterceptorStack$Proxy$
$$WeldClientProxy.next(Unknown Source)
br.com.caelum.vraptor.jpa.TransactionDecorator.intercept(TransactionDecorator.java:28)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:497)
org.jboss.weld.annotated.runtime.InvokableAnnotatedMethod.invokeOnInstance(InvokableAnnotatedMethod.java:97)
org.jboss.weld.bean.proxy.DecoratorProxyMethodHandler.doInvoke(DecoratorProxyMethodHandler.java:80)
org.jboss.weld.bean.proxy.DecoratorProxyMethodHandler.doInvoke(DecoratorProxyMethodHandler.java:69)
org.jboss.weld.interceptor.util.proxy.TargetInstanceProxyMethodHandler.invoke(TargetInstanceProxyMethodHandler.java:33)
org.jboss.weld.bean.proxy.TargetBeanInstance.invoke(TargetBeanInstance.java:88)
org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:100)
br.com.caelum.vraptor.jpa.JPATransactionInterceptor$Proxy$
$$Weld$Proxy$.intercept(Unknown Source)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:497)
org.jboss.weld.util.reflection.Reflections.invokeAndUnwrap(Reflections.java:401)
org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler.invoke(CombinedInterceptorAndDecoratorStackMethodHandler.java:62)
br.com.caelum.vraptor.jpa.JPATransactionInterceptor$Proxy$
$$WeldSubclass.intercept(Unknown Source)
br.com.caelum.vraptor.jpa.JPATransactionInterceptor$Proxy$
$$WeldClientProxy.intercept(Unknown Source)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:497)
net.vidageek.mirror.provider.java.PureJavaMethodReflectionProvider.invoke(PureJavaMethodReflectionProvider.java:38)
net.vidageek.mirror.invoke.MethodHandlerByMethod.withArgs(MethodHandlerByMethod.java:54)
br.com.caelum.vraptor.interceptor.StepInvoker.invokeMethod(StepInvoker.java:49)
br.com.caelum.vraptor.interceptor.StepInvoker.tryToInvoke(StepInvoker.java:40)
br.com.caelum.vraptor.interceptor.StepInvoker$Proxy$
$$WeldClientProxy.tryToInvoke(Unknown Source)
br.com.caelum.vraptor.interceptor.InterceptorExecutor.executeAround(InterceptorExecutor.java:75)
br.com.caelum.vraptor.interceptor.InterceptorExecutor$Proxy$
$$WeldClientProxy.executeAround(Unknown Source)
br.com.caelum.vraptor.interceptor.AspectStyleInterceptorHandler.execute(AspectStyleInterceptorHandler.java:85)
br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:83)
br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:75)
br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor$Proxy$
$$WeldClientProxy.intercept(Unknown Source)
br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:58)
br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:83)
br.com.caelum.vraptor.core.DefaultInterceptorStack.start(DefaultInterceptorStack.java:93)
br.com.caelum.vraptor.core.DefaultInterceptorStack$Proxy$
$$_WeldClientProxy.start(Unknown Source)
br.com.caelum.vraptor.observer.RequestHandlerObserver.handle(RequestHandlerObserver.java:93)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:497)
org.jboss.weld.injection.MethodInjectionPoint.invokeOnInstanceWithSpecialValue(MethodInjectionPoint.java:93)
org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:266)
org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:253)
org.jboss.weld.event.ObserverMethodImpl.notify(ObserverMethodImpl.java:232)
org.jboss.weld.event.ObserverNotifier.notifyObserver(ObserverNotifier.java:169)
org.jboss.weld.event.ObserverNotifier.notifyObserver(ObserverNotifier.java:165)
org.jboss.weld.event.ObserverNotifier.notifyObservers(ObserverNotifier.java:119)
org.jboss.weld.event.ObserverNotifier.fireEvent(ObserverNotifier.java:112)
org.jboss.weld.event.EventImpl.fire(EventImpl.java:83)
br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:123)

Inequality null comparisons

What about inequality comparisons with null? Any chance you could add an ExpressionType.IsNotNull just like ExpressionType.NotEqual exists for ExpressionType.Equal?
Right now, person -> person.getName() != null; gets evaluated to !(Is Null)P0.getName(). It is possible to evaluate that, but it's really dirty and probably also not very safe. Something like (Is Not Null)P0.getName() would be really great!

Nested expression tree when using parameters

I am currently improving my fork of the library lambda2sql which converts lambdas to SQL clauses using your library and have an issue when using parameters in the .and() or .or() methods in Predicate lambdas.

Here's some sample code:

SqlPredicate<IPerson> personPredicate = p -> p.getName() == "Donald";
personPredicate = personPredicate.and(p -> p.getName() == "Steve");

works fine and returns the desired output of name = 'Donald' AND name = 'Steve'.
But when I run this code:

var name1 = "Donald";
var name2 = "Steve";
SqlPredicate<IPerson> personPredicate = p -> p.getName() == name1;
personPredicate = personPredicate.and(p -> p.getName() == name2);

I get the output name = 'Donald' AND name = 'Donald'. Somehow the expression tree becomes nested with the second predicate and thus the ParameterExpression does not deliver the correct index value when going through the .visit(ParameterExpression) implementation. The index is 0 for the second Predicate, so it just grabs the first parameter again.

Get parameter value from ParameterExpression

When I analyze a lambda which contains a parameter, I can't seem to be able to extract that parameter. In the visit(ParameterExpression e) method it is only displayed as "P0" (for example). Is there any way to get the value of that parameter in the visit method? Here's an example:

String text = "Hello";
String part = "l";
Predicate<String> contains = s -> s.contains(part);

In this case I would like to extract the "l" from that lambda.

Incorrect parameter reference in MemberExpression

I've added an example for my problem below.
I am working on support for Java functions inside lambdas. But when traversing the expression tree, the parameter in the MemberExpression of the Java function is incorrect.
In my example, the parameter in the MemberExpression is P0, while it should be P1 which is the String parameter used for the startsWith method. In the full LambdaExpression that String is also marked as P1. P0 is the integer and has nothing to do with the startsWith check. Could you help me with this?

tree

Assignability in the TypeConverter 2

Whenever linking Predicates with the and method, the constructor of InvocationExpression throws an IllegalArgumentException. Somewhere along the way, the TypeConverter tries to compare a boolean to an int. And this, of course, does not work.
Here's the code I was running:

SqlPredicate<Person> predicate1 = person -> person.getAge() > 18;
SqlPredicate<Person> predicate2 = person -> person.getFirstName() == "Bob";
LambdaExpression<SqlPredicate<Person>> lambdaExpression = LambdaExpression.parse(predicate1.and(predicate2));

The only difference between an SqlPredicate<T> and a Predicate<T> is that the SqlPredicate<T> is serialized.

Update Maven artifact

Hi,

I couldn't help but notice that you have made some changes that are not included in the Maven artifact. I would really appreciate it if you could update the artifact with your latest changes.

Thanks a lot.

Jaque sources

Seems like email [email protected] isn't working and I haven't found other way to contact you, so excuse me for writing it here.
I know Jaque project is discontinued, but I would like to use it in my projects.
Current version only partially satisfies my needs and I want to fork from it (and I think I found some bugs there).
Apparently, I haven’t found sources at github (https://github.com/TrigerSoft/jaque/tree/master).
So, is there repository from where I can pull/fork?
Thanks in advance.

toString of a compound expression fails with an ArrayIndexOutOfBoundsException

Here's a test which i think should pass:

    interface SerializableFunction<T, R> extends Serializable, Function<T, R> {};

    @Test
    public void canToStringACompoundExpression() throws Exception {
        SerializableFunction<String, String> e = s -> s.substring(0, 1).toUpperCase();
        Expression body = LambdaExpression.parse(e).getBody();
        Assert.assertEquals("P0.substring(0, 1).toUpperCase()", body.toString());
    }

Using release 2.1.0, this fails with:

java.lang.ArrayIndexOutOfBoundsException: 0
    at java.util.Arrays$ArrayList.get(Arrays.java:3835)
    at java.util.Collections$UnmodifiableList.get(Collections.java:1369)
    at com.trigersoft.jaque.expression.InstanceAdaptor.visit(InstanceAdaptor.java:42)
    at com.trigersoft.jaque.expression.InstanceAdaptor.visit(InstanceAdaptor.java:26)
    at com.trigersoft.jaque.expression.ParameterExpression.visit(ParameterExpression.java:50)
    at com.trigersoft.jaque.expression.Expression.accept(Expression.java:1443)
    at com.trigersoft.jaque.expression.SimpleExpressionVisitor.visitExpressionList(SimpleExpressionVisitor.java:44)
    at com.trigersoft.jaque.expression.InstanceAdaptor.visit(InstanceAdaptor.java:52)
    at com.trigersoft.jaque.expression.InstanceAdaptor.visit(InstanceAdaptor.java:26)
    at com.trigersoft.jaque.expression.InvocationExpression.visit(InvocationExpression.java:50)
    at com.trigersoft.jaque.expression.Expression.accept(Expression.java:1443)
    at com.trigersoft.jaque.expression.SimpleExpressionVisitor.visit(SimpleExpressionVisitor.java:109)
    at com.trigersoft.jaque.expression.SimpleExpressionVisitor.visit(SimpleExpressionVisitor.java:30)
    at com.trigersoft.jaque.expression.MemberExpression.visit(MemberExpression.java:70)
    at com.trigersoft.jaque.expression.Expression.accept(Expression.java:1443)
    at com.trigersoft.jaque.expression.InstanceAdaptor.normalize(InstanceAdaptor.java:37)
    at com.trigersoft.jaque.expression.InvocationExpression.toString(InvocationExpression.java:107)

I don't actually care about toStringing expressions, but i was doing it for debugging and it blew up. It suggests that there is a deeper problem, with InstanceAdaptor. I don't understand what's going on in the code here, but in InstanceAdaptor there is a method:

    @Override
    public Expression visit(ParameterExpression e) {
        Expression x = args.get(e.getIndex());
        if (x instanceof ParameterExpression
                && ((ParameterExpression) x).getIndex() == e.getIndex())
            return e;
        return x;
    }

And here, args is an empty list, but e.getIndex() is 0. I assume this particular expression describes to the invocation of toUpperCase(), and i would guess that there is a mismatch between the number of formal parameters at the language level (zero) and the number at the bytecode level (one, for this).

Can not parse contains method

I pre-defined a list as below
List list = new ArrayList();
list.add(new Integer(1));
list.add(new Integer(2));
list.add(new Integer(3));
the i get an expression example : obj => list.contains(obj.Value)

Exception happend

Method references

There seems to be an issue when using a method reference instead of a lambda expression.
Take the simplified class

public class Person {
    private int age;
    public boolean isAdult() {
        return age >= 18;
    }
}

when using it in a lambda, I don't use person -> person.isAdult() (in a Predicate), but Person::isAdult. This results in the exception: java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0 in the convertArguments method of the ExpressionMethodVisitor class. When writing it as a lambda, it works fine.

Compile errors in master

I checked out the project and had over 200 compile errors, mainly from missing getters.
I fixed them and would like to contribute, because I was looking forward to build such a framework for implementing a ORM.

Passing null as a parameter

When using null in a lambda, e.g. SqlPredicate<IPerson> pred = p -> p.getName() == null; it becomes a UnaryExpression in the Expression tree and can be evaluated as such, which is great.

However when using a parameter that is null, e.g.:

String nullParam = null;
SqlPredicate<IPerson> p = person -> person.getName() == nullParam;

it gets evaluated as a normal ConstantExpression. Is there any way this could be changed?

Can not parse contains method

I pre-defined a list as below

List list = new ArrayList();
list.add(new Integer(1));
list.add(new Integer(2));
list.add(new Integer(3));
the i get an expression example : obj => list.contains(obj.Value)

Sorry, i means how can I convert this expression to sql statement as below:

where value in (1,2,3)

Java11 support

When building with java7 my integration test crashes with a UnsupportedOperationException("This feature requires ASM7"). Both ExpressionClassVisitor and ExpressionMethodVisitor are callign super with ASM5 - this seems to be the reason. I tried fixing it by using ASM7, but unfuortunately the tests fail on my machine (even with unchanged sources).

Adding a check for the java version might be useful in that case?

With my little fix https://github.com/spot-next/spot-framework/blob/develop/spot-core/src/test/java/io/spotnext/test/persistence/QueryLanguageIT.java (testLamdbaQuery) works fine again under OpenJDK 11

Consider using a lambda serialization hack to crack the lambdas

This is the approach used in Jinq:

https://github.com/my2iu/Jinq/blob/master/analysis/src/com/user00/thunk/SerializedLambda.java

The advantage of this approach over the dumpProxyClasses approach is that it does not require setting a system property or writing to the filesystem. Both of these things may be forbidden, or at least highly undesirable, in some situations.

One disadvantage is that it requires the input lambdas to be serializable, but this does not seem to be a particularly onerous requirement in practice. It may also be fragile in the face of changes in the definition of the JDK's SerializedLambda class, but i'm not sure about that.

Assignability in the TypeConverter 3

It seems I have found a concrete example for the issue with the Predicate#and method. When running this code:

long id = 1;
SqlPredicate<Person> personPredicate = person -> person.getId() == id;
SqlPredicate<Person> personSqlPredicateAnd = personPredicate.and(x -> true);
LambdaExpression<SqlPredicate<Person>> pred = LambdaExpression.parse(personSqlPredicateAnd);

I get the exception java.lang.IllegalArgumentException: 0 which is thrown in the constructor of the InvocationExpression class. When using the id as a constant and not as a variable, the exception doesn't get thrown.

Again, I am using JDK 11 and don't know if that has something to do with anything.

NoSuchMethodException in ExpressionMethodVisitor.visitMethodInsn if using method reference

Hello,

I have been trying the basic example, but for some reason it doesn't work.

This is what I have:

public class Test {
    
    public static void main(String[] args) {
        System.setProperty("jdk.internal.lambda.dumpProxyClasses", System.getProperty("java.io.tmpdir"));
        
        Fluent<Customer> f = new Fluent<>();
        System.out.println(f.property(customer -> customer.getName()).getParsed());
        //System.out.println(f.property(Customer::getName).getParsed());
    }
    
}

This works fine and prints: {(Customer P0) -> P0.getName()}

But if I try to replace the lambda with a method reference (as in the commented-out line), I get this exception:

Exception in thread "main" java.lang.RuntimeException: java.lang.NoSuchMethodException: java.lang.Object.getName()
	at com.trigersoft.jaque.expression.ExpressionMethodVisitor.visitMethodInsn(ExpressionMethodVisitor.java:756)
	at org.objectweb.asm.ClassReader.a(Unknown Source)
	at org.objectweb.asm.ClassReader.b(Unknown Source)
	at org.objectweb.asm.ClassReader.accept(Unknown Source)
	at org.objectweb.asm.ClassReader.accept(Unknown Source)
	at com.trigersoft.jaque.expression.ExpressionClassVisitor.parse(ExpressionClassVisitor.java:195)
	at com.trigersoft.jaque.expression.ExpressionClassVisitor.lambda(ExpressionClassVisitor.java:109)
	at com.trigersoft.jaque.expression.LambdaExpression.parse(LambdaExpression.java:91)
	at Fluent.property(Fluent.java:17)
	at Test.main(Test.java:8)
Caused by: java.lang.NoSuchMethodException: java.lang.Object.getName()
	at java.lang.Class.getDeclaredMethod(Class.java:2130)
	at com.trigersoft.jaque.expression.Expression.getDeclaredMethod(Expression.java:1277)
	at com.trigersoft.jaque.expression.Expression.invoke(Expression.java:1225)
	at com.trigersoft.jaque.expression.ExpressionMethodVisitor.visitMethodInsn(ExpressionMethodVisitor.java:753)
	... 9 more

Thanks for your work, have a good day.

Do not work with Oracle OpenJDK(version 1.8.0_40)

hello, i use the jaque
( the version is 2.4.4) for my framwork.
Some machines are running normally, but my colleague's machine reported an error when using my class library. The tracking stack information as follows:
db64be85a60db220406454b89dd2bd7a

I think there may be compatibility with the JDK version. If so, have you ever fixed this issue on your end?

IndexOutOfBoundsException when passing method reference as argument

Consider this method:

private SqlFunction<Person, Integer> getFunction(Person p) {
	if (p.getHeight() > 150) {
		return Person::getHeight;
	}
	return Person::getAge;
}

A SqlFunction is just a java.util.function.Function that implements Serializable.

Now, when I try to parse the function returned by the method like this: LambdaExpression.parse((SqlFunction<IPerson, ?>) this::getFunction);, I get the exception java.lang.IndexOutOfBoundsException: Index -1 out-of-bounds for length 0. However, if I do not pass a method reference, but a normal lambda like this: LambdaExpression.parse((SqlFunction<IPerson, ?>) p -> getFunction(p));, there is no exception and everything works.

Assignability in the TypeConverter

There seems to be an issue with the assignability between int and Integer in the class InvocationExpression. When parsing a lambda with Integer parameters, the constructor in the InvocationExpression throws an IllegalArgumentException. It seems to be because int is not assignable from Integer, or the other way around. Here is my stacktrace:

java.lang.IllegalArgumentException: 0

	at com.trigersoft.jaque.expression.InvocationExpression.<init>(InvocationExpression.java:42)
	at com.trigersoft.jaque.expression.Expression.invoke(Expression.java:1126)
	at com.trigersoft.jaque.expression.ExpressionClassCracker.lambda(ExpressionClassCracker.java:114)
	at com.trigersoft.jaque.expression.LambdaExpression.parse(LambdaExpression.java:91)

This is the code I was running:

int age = 80;
int height = 200;
SqlPredicate<Person> predicate = person -> person.getAge() == age && person.getHeight() > height;
LambdaExpression<SqlPredicate<Person>> lambda = LambdaExpression.parse(predicate);

EDIT:
It seems that this problem only appears when using parameters in lambdas. If I use constants, the exception is not thrown.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.