关闭

Java核心技术之脚本和编译

标签: java
216人阅读 评论(0) 收藏 举报
分类:

脚本

//创建一个脚本引擎管理器
ScriptEngineManager manager = new ScriptEngineManager();

//遍历引擎管理器所支持的所有脚本引擎
for (ScriptEngineFactory factory : manager.getEngineFactories()) {
    System.out.println(factory.getEngineName());
}

//根据引擎名字获取一个脚本引擎对象
final ScriptEngine engine = manager.getEngineByName("js");

//构造一个JFrame对象,里面包含一个JPanel和三个JButton对象
JFrame frame = (JFrame) Class.forName("buttons1.ButtonFrame").newInstance();

//向引擎对象中添加绑定(Bean的名字和实例的映射),这样在脚本的执行上下文中就可以访问Java对象(上面的UI对象)
private static void getComponentBindings(Component c, ScriptEngine engine) {
    String name = c.getName();
    if (name != null) engine.put(name, c);
    if (c instanceof Container) {
        for (Component child : ((Container) c).getComponents())
            getComponentBindings(child, engine);
    }
}

getComponentBindings(frame, engine);

//加载配置文件js.properties
/*
yellowButton.action=panel.background = java.awt.Color.YELLOW
blueButton.action=panel.background = java.awt.Color.BLUE
redButton.action=panel.background = java.awt.Color.RED
*/

final Properties events = new Properties();
InputStream in = frame.getClass().getResourceAsStream("js.properties");
events.load(in);

//根据配置文件设置三个按钮的点击监听器,监听器里面使用脚本引擎解析执行配置文件中相应JavaScript语句(第一个等号后面的内容)
for (final Object e : events.keySet()) {
    String[] s = ((String) e).split("\\.");
    addListener(s[0], s[1], (String) events.get(e), engine);
}

private static void addListener(String beanName, String eventName, final String scriptCode,
    final ScriptEngine engine) throws ReflectiveOperationException, IntrospectionException {
    Object bean = engine.get(beanName);
    EventSetDescriptor descriptor = getEventSetDescriptor(bean, eventName);
    if (descriptor == null) return;
    //使用动态代理生成一个对象
    descriptor.getAddListenerMethod().invoke(bean, Proxy.newProxyInstance(null, new Class[] { descriptor.getListenerType() }, 
        new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
                //解析JavaScript脚本
                engine.eval(scriptCode);
                return null;
            }
        }
    ));
}

private static EventSetDescriptor getEventSetDescriptor(Object bean, String eventName) throws IntrospectionException{
    for (EventSetDescriptor descriptor : Introspector.getBeanInfo(bean.getClass()).getEventSetDescriptors())
        if (descriptor.getName().equals(eventName)) return descriptor;
    return null;
}

编译

动态生成类

//构造一个JavaFileObject对象,用于编译
JavaFileObject source = buildSource("buttons2.ButtonFrame");
//动态生成了一个继承于buttons2.ButtonFrame的类x.Frame(包括包名)
static JavaFileObject buildSource(String superclassName) throws IOException, ClassNotFoundException {
    StringBuilderJavaSource source = new StringBuilderJavaSource("x.Frame");
    source.append("package x;\n");
    source.append("public class Frame extends " + superclassName + " {");
    source.append("protected void addEventHandlers() {");
    final Properties props = new Properties();
    props.load(Class.forName(superclassName).getResourceAsStream("action.properties"));
    for (Map.Entry<Object, Object> e : props.entrySet()) {
        String beanName = (String) e.getKey();
        String eventCode = (String) e.getValue();
        source.append(beanName + ".addActionListener(new java.awt.event.ActionListener() {");
        source.append("public void actionPerformed(java.awt.event.ActionEvent event) {");
        source.append(eventCode);
        source.append("} } );");
    }
    source.append("} }");
    return source;
}

//StringBuilderJavaSource类扩展了SimpleJavaFileObject类,如下:
public class StringBuilderJavaSource extends SimpleJavaFileObject {
    private StringBuilder code;

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

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

    public void append(String str) {
        code.append(str);
        code.append('\n');
    }
}

编译类

//用于存放编译后的结果
final List<ByteArrayJavaClass> classFileObjects = new ArrayList<>();
//编译器诊断输出对象
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
//JavaFileManager对象,将结果放入classFileObjects数组
JavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
fileManager = new ForwardingJavaFileManager<JavaFileManager>(fileManager) {
    public JavaFileObject getJavaFileForOutput(Location location, final String className,
                                               Kind kind, FileObject sibling) throws IOException {
        if (className.startsWith("x.")) {
            ByteArrayJavaClass fileObject = new ByteArrayJavaClass(className);
            classFileObjects.add(fileObject);
            return fileObject;
        } else return super.getJavaFileForOutput(location, className, kind, sibling);
    }
};
//ByteArrayJavaClass类如下
public class ByteArrayJavaClass extends SimpleJavaFileObject {
    private ByteArrayOutputStream stream;

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

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

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

//获取一个编译器对象
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

//创建一个编译任务并开始编译        
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, null, Arrays.asList(source));
boolean result = task.call();

使用类

//使用编译后的类集合构造一个自定义的ClassLoader,然后加载类x.Frame,并构造一个Frame的对象。
Map<String, byte[]> byteCodeMap = new HashMap<>();
for (ByteArrayJavaClass cl : classFileObjects)
    byteCodeMap.put(cl.getName().substring(1), cl.getBytes());
ClassLoader loader = new MapClassLoader(byteCodeMap);
JFrame frame = (JFrame) loader.loadClass("x.Frame").newInstance();

//最后自定义的MapClassLoader如下:
public class MapClassLoader extends ClassLoader {
    private Map<String, byte[]> classes;

    public MapClassLoader(Map<String, byte[]> classes) {
        this.classes = classes;
    }

    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classBytes = classes.get(name);
        if (classBytes == null) throw new ClassNotFoundException(name);
        Class<?> cl = defineClass(name, classBytes, 0, classBytes.length);
        if (cl == null) throw new ClassNotFoundException(name);
        return cl;
    }
}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:46632次
    • 积分:1151
    • 等级:
    • 排名:千里之外
    • 原创:37篇
    • 转载:2篇
    • 译文:12篇
    • 评论:6条
    最新评论