2014-11-26 3 views
0

Я создаю программу (исполняемый файл), которая позволяет пользователю играть с графиками и выполнять на них алгоритмы. В принципе, пользователь должен иметь возможность создать новый алгоритм, например модификацию Dijkstra, и попробовать его на графике. Тем не менее, я не уверен, что лучший способ запрограммировать это.Java позволяет пользователю создавать и выполнять алгоритмы

На данный момент я рассматриваю возможность использования Java-кода и его сохранение в отдельном каталоге. Однако я не знаю, возможно ли это, так как вам придется составлять Java-код вживую во время выполнения программы. Является ли этот метод жизнеспособным?

Другой способ - создать интерпретатор и позволить пользователю писать псевдокод, который затем будет сохранен и преобразован в то, что программа будет понимать. Однако, если предыдущий метод может быть выполнен, он может быть проще, чем этот.

Возможно ли использовать первый способ? Если да, то лучше второго? Или есть более простой способ сделать это?

+0

Вы должны рассмотреть вопросы безопасности позволяя пользователю создавать и запускать собственный код в вашей системе. – Grice

+0

Ну, программа должна запускаться в системе пользователя, это не апплет. – lost

+0

Похоже, вы хотите, чтобы API облегчил визуализацию алорифм с графиками. В то время как это так, вы не имеете никакого отношения к компиляции кода клиента, используя ваш API. Просто подумайте, что вы создаете то есть. Java Swing, заданный для графиков. –

ответ

0

Виртуальная машина Java имеет встроенный JavaScript engine, который вы можете использовать для своих целей. Вы можете загружать приложения и выполнять сценарии во время выполнения. Кроме того, вы можете легко вводить свои собственные объекты, реализуя любую функциональность, в которой вы нуждаетесь.

1

Вместо создания переводчика и изобретать велосипед, можно использовать уже существующий интерпретатор, такие как:

Для каждой из этих библиотек вы можете выбрать, чтобы некоторые классы относились к базовому языку как переменной.

+0

Это достойное решение. Использование Rhino и java скрипта выполняется быстро и легко .... –

0

Существует несколько вариантов этого, каждый из которых связан с различными усилиями и возможностями. Вы можете написать собственный интерпретатор или использовать существующий iterpreter, или использовать другой язык для разметки и использовать один из встроенных движков сценариев.

Однако, возвращаясь к исходному намерению, чтобы пользователь написал код Java, есть также опция для этого: если установлен JDK, вы можете использовать Java Tools JDK. (Обратите внимание, что это не будет работать с JRE).

В частности, вы можете использовать класс JavaCompiler для компиляции ваших классов Java на лету.

Я явно делаю НЕ хочу сказать, что это наиболее подходящее решение для вашей проблемы. Я просто хочу сказать, что это опция и что вы действительно можете скомпилировать Java-код на лету.

Когда я хотел просто ссылку на пример (или скопировать & пасту один, с указанием авторства), я заметил, что примеры, которые я нашел в Интернете либо plainly don't work или used temporary files, или только сосредоточены на некоторых конкретных аспектах JavaCompiler и его использование (представьте себе список ответов Blogs и StackOverflow здесь).

я не найти MCVE, который показал, как компилировать исходный код одного класса (или даже меньше: несколько классов), и загрузить полученный класс, полностью в памяти. Поэтому я создал такой класс утилиты: класс InMemoryCompiler может получить список имен классов и соответствующий исходный код и возвращает карту из имен классов в Class<?> объектов. Это можно будьте этим простыми, и это должно быть таким простым. Может быть, кто-то найдет это полезным.

import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.OutputStream; 
import java.io.PrintWriter; 
import java.lang.reflect.Method; 
import java.net.URI; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.LinkedHashMap; 
import java.util.List; 
import java.util.Locale; 
import java.util.Map; 

import javax.tools.FileObject; 
import javax.tools.ForwardingJavaFileManager; 
import javax.tools.JavaCompiler; 
import javax.tools.JavaCompiler.CompilationTask; 
import javax.tools.JavaFileManager; 
import javax.tools.JavaFileObject; 
import javax.tools.SimpleJavaFileObject; 
import javax.tools.ToolProvider; 

public class JavaCompilerExample 
{ 
    public static void main(String[] args) 
    { 
     String classNameA = "ExampleClassA"; 
     String sourceA = 
      "public class " + classNameA + " {" + "\n" + 
      " public static void main(String args[]) {" + "\n" + 
      "  System.out.println(\"Hello, compiler!\");" + "\n" + 
      "  ExampleClassB b = new ExampleClassB();" + "\n" + 
      "  b.someMethod();" + "\n" + 
      " }" + "\n" + 
      "}" + "\n"; 

     String classNameB = "ExampleClassB"; 
     String sourceB = 
      "public class " + classNameB + " {" + "\n" + 
      " public void someMethod() {" + "\n" + 
      "  System.out.println(\"Some method was called\");" + "\n" + 
      " }" + "\n" + 
      "}" + "\n"; 

     InMemoryCompiler c = new InMemoryCompiler(); 
     Map<String, Class<?>> classes = c.compile(
      Arrays.asList(classNameA, classNameB), 
      Arrays.asList(sourceA, sourceB)); 

     try 
     { 
      Class<?> exampleClass = classes.get(classNameA); 
      Method m = exampleClass.getDeclaredMethod("main", 
       new Class[] { String[].class }); 
      m.invoke(null, (Object) null); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 
} 

class InMemoryCompiler 
{ 
    private final Map<String, ByteArrayJavaFileObject> classFileObjects; 
    private final JavaCompiler javaCompiler; 
    private final JavaFileManager fileManager; 
    private final ClassLoader classLoader; 

    InMemoryCompiler() 
    { 
     classFileObjects = 
      new LinkedHashMap<String, ByteArrayJavaFileObject>(); 
     javaCompiler = ToolProvider.getSystemJavaCompiler(); 

     JavaFileManager standardFileManager = javaCompiler 
      .getStandardFileManager(null, Locale.ENGLISH, null); 
     fileManager = new CompiledFileManager(standardFileManager); 
     classLoader = new CompiledClassLoader(); 
    } 

    public Map<String, Class<?>> compile(
     List<String> classNames, List<String> sources) 
    { 
     List<JavaFileObject> javaFileObjects = new ArrayList<JavaFileObject>(); 
     for (int i = 0; i < classNames.size(); i++) 
     { 
      String className = classNames.get(i); 
      String source = sources.get(i); 
      javaFileObjects.add(new StringJavaFileObject(className, source)); 
     } 
     CompilationTask compilationTask = javaCompiler.getTask(
      new PrintWriter(System.out), fileManager, null, null, null, 
      javaFileObjects); 
     compilationTask.call(); 

     Map<String, Class<?>> classes = new LinkedHashMap<String, Class<?>>(); 
     for (int i = 0; i < classNames.size(); i++) 
     { 
      String className = classNames.get(i); 
      try 
      { 
       Class<?> c = classLoader.loadClass(className); 
       classes.put(className, c); 
      } 
      catch (ClassNotFoundException e) 
      { 
       System.out.println(e); 
      } 
     } 
     return classes; 
    } 

    private class CompiledFileManager 
     extends ForwardingJavaFileManager<JavaFileManager> 
    { 
     CompiledFileManager(JavaFileManager fileManager) 
     { 
      super(fileManager); 
     } 

     @Override 
     public JavaFileObject getJavaFileForOutput(Location location, 
      String className, javax.tools.JavaFileObject.Kind kind, 
      FileObject sibling) throws IOException 
     { 
      ByteArrayJavaFileObject javaFileObject = 
       new ByteArrayJavaFileObject(className); 
      classFileObjects.put(className, javaFileObject); 
      return javaFileObject; 
     } 
    } 

    private class CompiledClassLoader extends ClassLoader 
    { 
     @Override 
     public Class<?> findClass(String name) 
     { 
      byte[] b = classFileObjects.get(name).getBytes(); 
      return defineClass(name, b, 0, b.length); 
     } 
    } 

    private class ByteArrayJavaFileObject extends SimpleJavaFileObject 
    { 
     private final ByteArrayOutputStream stream; 

     public ByteArrayJavaFileObject(String name) 
     { 
      super(URI.create("bytes:///" + name), Kind.CLASS); 
      stream = new ByteArrayOutputStream(); 
     } 

     @Override 
     public OutputStream openOutputStream() throws IOException 
     { 
      return stream; 
     } 

     public byte[] getBytes() 
     { 
      return stream.toByteArray(); 
     } 
    } 

    private class StringJavaFileObject extends SimpleJavaFileObject 
    { 
     private final String code; 

     StringJavaFileObject(String name, String code) 
     { 
      super(URI.create("string:///" + name.replace('.', '/') + 
       Kind.SOURCE.extension), Kind.SOURCE); 
      this.code = code; 
     } 

     @Override 
     public CharSequence getCharContent(boolean ignoreEncodingErrors) 
     { 
      return code; 
     } 
    } 

} 

(Примечание: Существует едва ли любой обработки ошибок в этом классе Она может быть расширена с помощью DiagnosticListener и такие, но это не главное намерение здесь.)

Смежные вопросы