greenjoe / lambdafromstring Goto Github PK
View Code? Open in Web Editor NEWJava library that can create a lambda from its code stored in a string.
License: MIT License
Java library that can create a lambda from its code stored in a string.
License: MIT License
Hi all,
I have found a problem using this library when compiling the following lambda:
....map(word -> new SimpleEntry<String, Long>(word, (long) 1))...
The problem consists of an undesired repetition in the package name of the SimpleEntry class, which makes the compilation process to fail (i.e., java.util.AbstractMap.java.util.AbstractMap$SimpleEntry does not exist). Also, instead of a '.', the SimpleEntry name was preceded of a '$' symbol, which is also a source of problems.
After some debugging, I found where the problem arises: the createLambda method in the LambdaFactory class. The problem comes when the typeReference.toString() is invoked, returning a malformed class name for SimpleEntry class.
To bypass this problem at the moment, I created a "sanity check" method that inspects if the class name returned by typeReference.toString() has duplicates or not, and deletes them in the affirmative case. This works for my case as well as for the test cases provided in the library. However, maybe this can be solved in a much better way by addressing the root cause of why typeReference.toString() sometimes does not behave properly.
Thanks a lot,
Raúl.
@scott-a-miller created a Pull Request #4 in which he adds a possibility to create lambdas with dynamic type references.
Finding and implementing the best way to achieve that feature is the scope if this issue. It should be possible to pass a dynamic string as a TypeReference when the type is unknown during the compilation phase.
Hi,
Your project looks really promising and I would like to try and use it in one of our products, but it has a major limitation, that is, the dependency on the JDK.
It is a known fact that tools.jar cannot be a part of the distribution, but there is a good alternative - ECJ.
http://mvnrepository.com/artifact/org.eclipse.jdt.core.compiler/ecj
Could you consider using it instead?
below is the error message
pl.joegreen.lambdaFromString.LambdaCreationException: pl.joegreen.lambdaFromString.classFactory.ClassCompilationException: Class compilation details:
Class name: LambdaFromStringHelper
Class source:
import java.util.function.*;
import java.util.Map;
import java.util.HashMap;
import static com.custom.Functions.*;
public class LambdaFromStringHelper {
public static java.util.function.BiFunction<java.util.Map<java.lang.String, java.lang.Object>, java.util.Map<java.lang.String, java.lang.Object>, java.lang.Boolean> getLambda() {return ((ds1, ds2) -> binary_relational_operate("==", ds1.get("CASEID"), ds2.get("CASEID")));}
}
Compiler messages:
ERROR: The import com.custom cannot be resolved
ERROR: The method binary_relational_operate(java.lang.String, java.lang.Object, java.lang.Object) is undefined for the type LambdaFromStringHelper
Compiler standard error output:
----------
1. ERROR in \LambdaFromStringHelper.java (at line 4)
import static com.custom.Functions.*;
^^^^^^^^^^^^^^^
The import com.custom cannot be resolved
----------
2. ERROR in \LambdaFromStringHelper.java (at line 7)
public static java.util.function.BiFunction<java.util.Map<java.lang.String, java.lang.Object>, java.util.Map<java.lang.String, java.lang.Object>, java.lang.Boolean> getLambda() {return ((ds1, ds2) -> binary_relational_operate("==", ds1.get("CASEID"), ds2.get("CASEID")));}
^^^^^^^^^^^^^^^^^^^^^^^^^
The method binary_relational_operate(String, Object, Object) is undefined for the type LambdaFromStringHelper
----------
2 problems (2 errors)
at pl.joegreen.lambdaFromString.LambdaFactory.createLambda(LambdaFactory.java:83)
at com.custom.SimpleSelectTransformer.doTransform(SimpleSelectTransformer.java:362)
at ...
at java.lang.Thread.run(Unknown Source)
Caused by: pl.joegreen.lambdaFromString.classFactory.ClassCompilationException: Class compilation details:
Class name: LambdaFromStringHelper
Class source:
import java.util.function.*;
import java.util.Map;
import java.util.HashMap;
import static com.custom.Functions.*;
public class LambdaFromStringHelper {
public static java.util.function.BiFunction<java.util.Map<java.lang.String, java.lang.Object>, java.util.Map<java.lang.String, java.lang.Object>, java.lang.Boolean> getLambda() {return ((ds1, ds2) -> binary_relational_operate("==", ds1.get("CASEID"), ds2.get("CASEID")));}
}
Compiler messages:
ERROR: The import com.custom cannot be resolved
ERROR: The method binary_relational_operate(java.lang.String, java.lang.Object, java.lang.Object) is undefined for the type LambdaFromStringHelper
Compiler standard error output:
----------
1. ERROR in \LambdaFromStringHelper.java (at line 4)
import static com.custom.Functions.*;
^^^^^^^^^^^^^^^
The import com.custom cannot be resolved
----------
2. ERROR in \LambdaFromStringHelper.java (at line 7)
public static java.util.function.BiFunction<java.util.Map<java.lang.String, java.lang.Object>, java.util.Map<java.lang.String, java.lang.Object>, java.lang.Boolean> getLambda() {return ((ds1, ds2) -> binary_relational_operate("==", ds1.get("CASEID"), ds2.get("CASEID")));}
^^^^^^^^^^^^^^^^^^^^^^^^^
The method binary_relational_operate(String, Object, Object) is undefined for the type LambdaFromStringHelper
----------
2 problems (2 errors)
at pl.joegreen.lambdaFromString.classFactory.DefaultClassFactory.compileClasses(DefaultClassFactory.java:56)
at pl.joegreen.lambdaFromString.classFactory.DefaultClassFactory.createClass(DefaultClassFactory.java:24)
at pl.joegreen.lambdaFromString.LambdaFactory.createLambda(LambdaFactory.java:72)
... 11 more
I have a lambda expression expression makes a service call:
Predicate onMP = obj -> (Boolean)reportsService.parseMethods("onMortgagePlan[2017]", obj);
where reportsService
is an autowired local reference to a service class.
When I attempt to create this lambda using LambdaFactory
LambdaFactory lambdaFactory = LambdaFactory.get(
LambdaFactoryConfiguration.get().withImports(Project.class));
Function<Project, Boolean> onMP = lambdaFactory.createLambda(
"obj -> (Boolean)reportsService.parseMethods("onMortgagePlan[2017]", obj)",
new TypeReference<Function<Project, Boolean>>(){});
I get a ClassCompilationException
:
Class name: LambdaFromStringHelper
Class source:
import java.util.function.*;
import gov.lanl.queue.model.entity.project.Project;public class LambdaFromStringHelper {
public static java.util.function.Function<gov.lanl.queue.model.entity.project.Project, > java.lang.Boolean> getLambda() {return (obj -> (Boolean)reportsService.parseMethods("onMortgagePlan[2017]", obj));}
}
Compiler messages:
ERROR: cannot find symbol
symbol: variable reportsService
location: class LambdaFromStringHelper
Compiler standard error output:
Is there any way to make this work?
Only Java 8 is supported.
Are there plans to support Java 11?
Or is it impossible for some reason? Why?
Right now only Java standard library classes/interfaces can be used in lambda code as only those classes are available on classpath during the compilation process. If user could add custom directories/jar files to the compilation classpath it should be possible to compile lambdas that use other classes or interfaces.
Class loading mechanism should also be checked as Java treats same classes as different if they were loaded by a different classloaders - it might cause problems if user loads his class/interface and then lambdaFromString loads it again using its class loader when loading lambda code.
Interface proposition: classpath entries as List configured the same way as imports in LambdaFactoryConfiguration
I get the problem using 'org.eclipse.jdt.core.compiler:ecj:4.6.1'
on runtime.
Env:
openjdk version "17.0.8" 2023-07-18
OpenJDK Runtime Environment Temurin-17.0.8+7 (build 17.0.8+7)
8 problems (8 errors)
LambdaFromString currently loads lambda code without any validation - the code might do anything (call System.exit(0), use file system, send network packets and so on). Letting someone provide a code for lambda and then loading and executing it is as secure as giving that person permission to edit application code. Java platform usually uses SecurityManager to limit permissions of classes that are loaded from external sources. LambdaFromString could probably use that to do the same.
I ran the app on tomcat Server 8.5.
My application is a web application using Tomcat 8.5 Java 8, ZK 8.0.3
I ran from-string lambda lambda-1.4.
`public class ChitieuGiao implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Double trongsochung = 0d;
private Double chitieugiao = 0d;
private Double tylethuchien = 0d;
private Date createTime = new Date();
private String createUser;
/** default constructor */
public ChitieuGiao() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public Double getTrongsochung() {
return this.trongsochung;
}
public void setTrongsochung(Double trongsochung) {
this.trongsochung = trongsochung;
}
public Double getChitieugiao() {
return this.chitieugiao;
}
public void setChitieugiao(Double chitieugiao) {
this.chitieugiao = chitieugiao;
}
public Double getTylethuchien() {
return this.tylethuchien;
}
public void setTylethuchien(Double tylethuchien) {
this.tylethuchien = tylethuchien;
}
public String getCreateUser() {
return this.createUser;
}
public void setCreateUser(String createUser) {
this.createUser = createUser;
}
public Date getCreateTime() {
return this.createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}`
Code run
`
@command("onExecuted")
@OverRide
public void onExecuted() {
try {
exlambda();
} catch (ParseException e) {
e.printStackTrace();
}
}
public void exlambda() {
ChitieuGiao chitieu = new ChitieuGiao();
chitieu.setCreateTime(new Date());
chitieu.setChitieugiao(9000000000000d);
chitieu.setTrongsochung(9.0);
chitieu.setTylethuchien(89.0);
String code = codeTest();
try {
LambdaFactory factory = LambdaFactory.get(LambdaFactoryConfiguration.get().withImports(ChitieuGiao.class));
Function<ChitieuGiao, Double> lambda = factory.createLambdaUnchecked("tinhdiem -> { " + code + "}",
new TypeReference<Function<ChitieuGiao, Double>>() {
});
System.out.println(lambda.apply(chitieu));
} catch (Exception e) {
e.printStackTrace();
}
}
public String codeTest() {
String code = "";
code = "Double tylethuchien = tinhdiem.getTylethuchien();";
code += "Double diemhoanthanh = (double) 0;";
code += "if (tylethuchien <= 100) {";
code += " diemhoanthanh = tylethuchien;";
code += "} else if (tylethuchien > 100 && tylethuchien < 105) {";
code += " diemhoanthanh = 100 + 3 * (tylethuchien - 100);";
code += "} else if (tylethuchien >= 105 && tylethuchien < 110) {";
code += " diemhoanthanh = 100 + 3 * 5 + 5 * (tylethuchien - 105);";
code += "} else if (tylethuchien >= 110 && tylethuchien < 120) {";
code += " diemhoanthanh = 100 + 3 * 5 + 5 * 5 + 7 * (tylethuchien - 110);";
code += "}";
code += "return diemhoanthanh;";
return code;
}`
`pl.joegreen.lambdaFromString.LambdaCreationRuntimeException: pl.joegreen.lambdaFromString.classFactory.ClassCompilationException: Class compilation details:
Class name: LambdaFromStringHelper
Class source:
import java.util.function.*;
import com.evnit.hrms.viewmodel.kpi.ChitieuGiao;
3 problems (3 errors)
at pl.joegreen.lambdaFromString.LambdaFactory.createLambdaUnchecked(LambdaFactory.java:101)
at com.evnit.hrms.viewmodel.kpi.KyApDungVM.exlambda(KyApDungVM.java:123)
at com.evnit.hrms.viewmodel.kpi.KyApDungVM.onNew(KyApDungVM.java:101)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.zkoss.bind.impl.ParamCall.call(ParamCall.java:149)
at org.zkoss.bind.impl.BinderImpl.doExecute(BinderImpl.java:2025)
at org.zkoss.bind.impl.BinderImpl.doCommand(BinderImpl.java:1738)
at org.zkoss.bind.impl.BinderImpl.access$1300(BinderImpl.java:129)
at org.zkoss.bind.impl.BinderImpl$CommandEventListener.onEvent0(BinderImpl.java:1585)
at org.zkoss.bind.impl.BinderImpl$CommandEventListener.onEvent(BinderImpl.java:1538)
at org.zkoss.zk.ui.AbstractComponent.onEvent(AbstractComponent.java:3163)
at org.zkoss.zk.ui.AbstractComponent.service(AbstractComponent.java:3133)
at org.zkoss.zk.ui.AbstractComponent.service(AbstractComponent.java:3075)
at org.zkoss.zk.ui.impl.EventProcessor.process(EventProcessor.java:138)
at org.zkoss.zk.ui.impl.EventProcessingThreadImpl.process0(EventProcessingThreadImpl.java:545)
at org.zkoss.zk.ui.impl.EventProcessingThreadImpl.run(EventProcessingThreadImpl.java:470)
Caused by: pl.joegreen.lambdaFromString.classFactory.ClassCompilationException: Class compilation details:
Class name: LambdaFromStringHelper
Class source:
import java.util.function.*;
import com.evnit.hrms.viewmodel.kpi.ChitieuGiao;
3 problems (3 errors)
at pl.joegreen.lambdaFromString.classFactory.DefaultClassFactory.compileClasses(DefaultClassFactory.java:54)
at pl.joegreen.lambdaFromString.classFactory.DefaultClassFactory.createClass(DefaultClassFactory.java:24)
at pl.joegreen.lambdaFromString.LambdaFactory.createLambda(LambdaFactory.java:72)
at pl.joegreen.lambdaFromString.LambdaFactory.createLambdaUnchecked(LambdaFactory.java:99)
... 18 more
`
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.