Last active
February 17, 2017 10:00
-
-
Save serge1/082be1138bce8f52270675fc923fc72b to your computer and use it in GitHub Desktop.
Eclipse View project that demonstrates JavaScript and Java dynamic compilation and inter operability
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package jstest.views; | |
import javax.tools.*; | |
import java.io.ByteArrayOutputStream; | |
import java.io.IOException; | |
import java.io.OutputStream; | |
import java.lang.reflect.InvocationTargetException; | |
import java.net.URI; | |
import java.security.SecureClassLoader; | |
import java.util.ArrayList; | |
import java.util.List; | |
// Based on: http://javapracs.blogspot.cz/2011/06/dynamic-in-memory-compilation-using.html | |
public class DynamicCompiler { | |
//private static final Logger logger = LoggerFactory.getLogger(DynamicCompiler.class); | |
private JavaFileManager fileManager; | |
private String fullName; | |
private String sourceCode; | |
public DynamicCompiler(String fullName, String srcCode) { | |
this.fullName = fullName; | |
this.sourceCode = srcCode; | |
this.fileManager = initFileManager(); | |
} | |
public JavaFileManager initFileManager() { | |
if (fileManager != null) | |
return fileManager; | |
else { | |
System.setProperty("java.home", "c:\\Program Files (x86)\\Java\\jdk1.8.0_92"); | |
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); | |
fileManager = new | |
ClassFileManager(compiler | |
.getStandardFileManager(null, null, null)); | |
return fileManager; | |
} | |
} | |
public void compile() { | |
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); | |
List<JavaFileObject> files = new ArrayList<>(); | |
files.add(new CharSequenceJavaFileObject(fullName, sourceCode)); | |
compiler.getTask( | |
null, | |
fileManager, | |
null, | |
null, | |
null, | |
files | |
).call(); | |
} | |
public Class<?> get() { | |
Class<?> ret = null; | |
try { | |
ret = fileManager | |
.getClassLoader(null) | |
.loadClass(fullName); | |
} catch (ClassNotFoundException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
return ret; | |
} | |
public void run() throws InstantiationException, IllegalAccessException, ClassNotFoundException { | |
try { | |
fileManager | |
.getClassLoader(null) | |
.loadClass(fullName) | |
.getDeclaredMethod("main", new Class[]{String[].class}) | |
.invoke(null, new Object[]{null}); | |
} catch (InvocationTargetException e) { | |
System.out.print("InvocationTargetException"); | |
//logger.error("InvocationTargetException:", e); | |
} catch (NoSuchMethodException e) { | |
System.out.print("NoSuchMethodException "); | |
//logger.error("NoSuchMethodException:", e); | |
} | |
} | |
public class CharSequenceJavaFileObject extends SimpleJavaFileObject { | |
/** | |
* CharSequence representing the source code to be compiled | |
*/ | |
private CharSequence content; | |
public CharSequenceJavaFileObject(String className, CharSequence content) { | |
super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); | |
this.content = content; | |
} | |
public CharSequence getCharContent(boolean ignoreEncodingErrors) { | |
return content; | |
} | |
} | |
@SuppressWarnings("rawtypes") | |
public class ClassFileManager extends ForwardingJavaFileManager { | |
private JavaClassObject javaClassObject; | |
@SuppressWarnings("unchecked") | |
public ClassFileManager(StandardJavaFileManager standardManager) { | |
super(standardManager); | |
} | |
@Override | |
public ClassLoader getClassLoader(Location location) { | |
return new SecureClassLoader() { | |
@Override | |
protected Class<?> findClass(String name) throws ClassNotFoundException { | |
byte[] b = javaClassObject.getBytes(); | |
return super.defineClass(name, javaClassObject.getBytes(), 0, b.length); | |
} | |
}; | |
} | |
public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { | |
this.javaClassObject = new JavaClassObject(className, kind); | |
return this.javaClassObject; | |
} | |
} | |
public class JavaClassObject extends SimpleJavaFileObject { | |
protected final ByteArrayOutputStream bos = | |
new ByteArrayOutputStream(); | |
public JavaClassObject(String name, Kind kind) { | |
super(URI.create("string:///" + name.replace('.', '/') | |
+ kind.extension), kind); | |
} | |
public byte[] getBytes() { | |
return bos.toByteArray(); | |
} | |
@Override | |
public OutputStream openOutputStream() throws IOException { | |
return bos; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- Start a wizard for new Eclipse Plug-in Project | |
- Give project name "jstest" | |
- Select "Plug-in with a view" | |
- Give a View Class Name "JSTestView" (and use "Table viewer") | |
- Substitute the generated source files and add the files from here |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package jstest.views; | |
import org.eclipse.swt.widgets.Button; | |
import org.eclipse.swt.widgets.Composite; | |
import org.eclipse.swt.widgets.Label; | |
import org.eclipse.ui.part.*; | |
import org.eclipse.jface.viewers.*; | |
import org.eclipse.swt.graphics.Image; | |
import org.eclipse.swt.layout.GridData; | |
import org.eclipse.swt.layout.GridLayout; | |
import java.util.ArrayList; | |
import java.util.function.Predicate; | |
import java.util.stream.Collectors; | |
import javax.script.Invocable; | |
import javax.script.ScriptEngine; | |
import javax.script.ScriptEngineManager; | |
import javax.script.ScriptException; | |
import org.eclipse.ui.*; | |
import org.eclipse.swt.widgets.Text; | |
import org.eclipse.swt.SWT; | |
import org.eclipse.swt.events.SelectionEvent; | |
import org.eclipse.swt.events.SelectionListener; | |
/** | |
* This sample class demonstrates how to plug-in a new workbench view. The view | |
* shows data obtained from the model. The sample creates a dummy model on the | |
* fly, but a real implementation would connect to the model available either in | |
* this or another plug-in (e.g. the workspace). The view is connected to the | |
* model using a content provider. | |
* <p> | |
* The view uses a label provider to define how model objects should be | |
* presented in the view. Each view can present the same model objects using | |
* different labels and icons, if needed. Alternatively, a single label provider | |
* can be shared between views in order to ensure that objects of the same type | |
* are presented in the same way everywhere. | |
* <p> | |
*/ | |
public class JSTestView extends ViewPart { | |
/** | |
* The ID of the view as specified by the extension. | |
*/ | |
public static final String ID = "jstest.views.JSTestView"; | |
private TableViewer viewer; | |
private final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); | |
private final ArrayList<String> array = new ArrayList<String>(); | |
private ArrayList<String> arrayToShow; | |
private Text filter; | |
private Text filter1; | |
private final MySelectionListener mySelectionListener = new MySelectionListener(); | |
private final MySelectionListener1 mySelectionListener1 = new MySelectionListener1(); | |
class ViewLabelProvider extends LabelProvider implements ITableLabelProvider { | |
public String getColumnText(Object obj, int index) { | |
return getText(obj); | |
} | |
public Image getColumnImage(Object obj, int index) { | |
return getImage(obj); | |
} | |
public Image getImage(Object obj) { | |
return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT); | |
} | |
} | |
/** | |
* The constructor. | |
*/ | |
public JSTestView() { | |
array.add("One"); | |
array.add("Two"); | |
array.add("Three"); | |
array.add("Four"); | |
array.add("Five"); | |
array.add("Six"); | |
arrayToShow = array.stream().collect(Collectors.toCollection(ArrayList::new)); | |
} | |
private static Boolean safeInvokeFunction(Invocable invocable, String param1, String param2) { | |
try { | |
return (Boolean) invocable.invokeFunction(param1, param2); | |
} catch (NoSuchMethodException | ScriptException e) { | |
// e.printStackTrace(); | |
} | |
return false; | |
} | |
/** | |
* This is a callback that will allow us to create the viewer and initialize | |
* it. | |
*/ | |
public void createPartControl(Composite parent) { | |
GridLayout layout = new GridLayout(3, false); | |
parent.setLayout(layout); | |
Label filterLabel = new Label(parent, SWT.NONE); | |
filterLabel.setText("Filter: "); | |
filter = new Text(parent, SWT.BORDER | SWT.SEARCH); | |
filter.addSelectionListener(mySelectionListener); | |
final Button filterApplyButton = new Button(parent, SWT.PUSH); | |
filterApplyButton.setText("Apply JavaScript"); | |
filterApplyButton.addSelectionListener(mySelectionListener); | |
filter.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); | |
Label filterLabel1 = new Label(parent, SWT.NONE); | |
filterLabel1.setText("Filter: "); | |
filter1 = new Text(parent, SWT.BORDER | SWT.SEARCH); | |
filter1.addSelectionListener(mySelectionListener1); | |
filter1.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); | |
final Button filterApplyButton1 = new Button(parent, SWT.PUSH); | |
filterApplyButton1.setText("Apply Java"); | |
filterApplyButton1.addSelectionListener(mySelectionListener1); | |
viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); | |
viewer.setContentProvider(ArrayContentProvider.getInstance()); | |
viewer.setInput(arrayToShow); | |
viewer.setLabelProvider(new ViewLabelProvider()); | |
GridData gridData = new GridData(); | |
gridData.verticalAlignment = GridData.FILL; | |
gridData.horizontalSpan = 3; | |
gridData.grabExcessHorizontalSpace = true; | |
gridData.grabExcessVerticalSpace = true; | |
gridData.horizontalAlignment = GridData.FILL; | |
viewer.getControl().setLayoutData(gridData); | |
// Create the help context id for the viewer's control | |
PlatformUI.getWorkbench().getHelpSystem().setHelp(viewer.getControl(), "jstest.viewer"); | |
getSite().setSelectionProvider(viewer); | |
} | |
/** | |
* Passing the focus request to the viewer's control. | |
*/ | |
public void setFocus() { | |
viewer.getControl().setFocus(); | |
} | |
private class MySelectionListener implements SelectionListener { | |
@Override | |
public void widgetSelected(SelectionEvent e) { | |
doIt(); | |
} | |
@Override | |
public void widgetDefaultSelected(SelectionEvent e) { | |
doIt(); | |
} | |
private void doIt() { | |
String condition = filter.getText(); | |
condition = condition.trim(); | |
if (condition.isEmpty()) { | |
condition = "true"; | |
} | |
String myScript = ""; | |
myScript += "var checkIt = function(text) {"; | |
myScript += " if (" + condition + ")"; | |
myScript += " return true;"; | |
myScript += " else"; | |
myScript += " return false;"; | |
myScript += "}"; | |
try { | |
engine.eval(myScript); | |
Invocable invocable = (Invocable) engine; | |
arrayToShow = array.stream().filter(t -> safeInvokeFunction(invocable, "checkIt", t)) | |
.collect(Collectors.toCollection(ArrayList::new)); | |
viewer.setInput(arrayToShow); | |
} catch (ScriptException e1) { | |
// TODO Auto-generated catch block | |
e1.printStackTrace(); | |
} | |
} | |
} | |
private class MySelectionListener1 implements SelectionListener { | |
@Override | |
public void widgetSelected(SelectionEvent e) { | |
doIt(); | |
} | |
@Override | |
public void widgetDefaultSelected(SelectionEvent e) { | |
doIt(); | |
} | |
/** | |
* | |
*/ | |
private void doIt() { | |
String condition = filter1.getText(); | |
condition = condition.trim(); | |
if (condition.isEmpty()) { | |
condition = "true"; | |
} | |
String className = "jstest.views.MyJavaFilter"; | |
String code = "" | |
+ "package jstest.views;\n" | |
+ "import java.util.function.Predicate;\n" | |
+ "public class MyJavaFilter implements Predicate<String> {\n" | |
+ " @Override\n" | |
+ " public boolean test(String value) {\n" | |
+ " if (" + condition + ")\n" | |
+ " return true;\n" | |
+ " else\n" | |
+ " return false;\n" | |
+ " }\n" | |
+ "}\n"; | |
DynamicCompiler compiler = new DynamicCompiler(className, code); | |
compiler.compile(); | |
try { | |
Class<?> myClass = compiler.get(); | |
@SuppressWarnings("unchecked") | |
Predicate<String> myTest = (Predicate<String>) myClass.newInstance(); | |
arrayToShow = array.stream() | |
.filter(myTest) | |
.collect(Collectors.toCollection(ArrayList::new)); | |
viewer.setInput(arrayToShow); | |
} catch (InstantiationException | IllegalAccessException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment