精华内容
下载资源
问答
  • cglib动态生成java类

    2014-01-26 15:17:53
    cglib动态生成java类
  • ASM操作字节码,动态生成Java类class文件,模拟Spring的AOP实现原理。
  • 考虑这种情况:我有一个名为person.xml的XML文件,其中包含以下数据.MrFoo28如果我想将这个XML读入Java对象,我将创建一个名为PersonBean的Java bean(使用属性的getter / setter):class Person{String name;...

    考虑这种情况:我有一个名为person.xml的

    XML文件,其中包含以下数据.

    MrFoo

    28

    如果我想将这个XML读入Java对象,我将创建一个名为PersonBean的Java bean(使用属性的getter / setter):

    class Person{

    String name;

    int age;

    }

    我可以使用任何API来读取XML并填充Java Bean.

    但这里真正的问题是,假设XML文件的结构发生了变化,即如果将新属性“email”添加到XML文件中,那么我还必须修改Java Bean以添加新属性.但是,即使XML结构发生变化,我也希望避免更改Java代码.

    所以,我正在尝试做的是,我正在创建另一个名为PersonStructure.xml的XML文件,其内容为:

    personName

    java.lang.String

    ... and it goes like this...

    是否可以读取PersonStructure.XML文件并将其转换为Person.Java类文件?我正在尝试做的方法是正确的还是还有其他方法可以做同样的事情吗?

    展开全文
  • Java是一门静态语言,通常,我们需要的class在编译的时候就已经生成了,为什么有时候我们还想在运行时动态生成class呢?因为在有些时候,我们还真得在运行时为一个动态创建子类。比如,编写一个ORM框架,如何得知...

    Java是一门静态语言,通常,我们需要的class在编译的时候就已经生成了,为什么有时候我们还想在运行时动态生成class呢?

    因为在有些时候,我们还真得在运行时为一个类动态创建子类。比如,编写一个ORM框架,如何得知一个简单的JavaBean是否被用户修改过呢?

    以User为例:

    public classUser {privateString id;privateString name;publicString getId() {returnid;

    }public voidsetId(String id) {this.id =id;

    }publicString getName() {returnname;

    }public voidsetName(String name) {this.name =name;

    }

    }

    其实UserProxy实现起来很简单,就是创建一个User的子类,覆写所有setXxx()方法,做个标记就可以了:

    public class UserProxy extendsUser {private booleandirty;public booleanisDirty() {return this.dirty;

    }public void setDirty(booleandirty) {this.dirty =dirty;

    }

    @Overridepublic voidsetId(String id) {super.setId(id);

    setDirty(true);

    }

    @Overridepublic voidsetName(String name) {super.setName(name);

    setDirty(true);

    }

    }

    但是这个UserProxy就必须在运行时动态创建出来了,因为编译时ORM框架根本不知道User类。

    现在问题来了,动态生成字节码,难度有多大?

    如果我们要自己直接输出二进制格式的字节码,在完成这个任务前,必须先认真阅读JVM规范第4章,详细了解class文件结构。估计读完规范后,两个月过去了。

    所以,第一种方法,自己动手,从零开始创建字节码,理论上可行,实际上很难。

    第二种方法,使用已有的一些能操作字节码的库,帮助我们创建class。

    目前,能够操作字节码的开源库主要有CGLib和Javassist两种,它们都提供了比较高级的API来操作字节码,最后输出为class文件。

    比如CGLib,典型的用法如下:

    Enhancer e = newEnhancer();

    e.setSuperclass(...);

    e.setStrategy(newDefaultGeneratorStrategy() {protectedClassGenerator transform(ClassGenerator cg) {return newTransformingGenerator(cg,new AddPropertyTransformer(new String[]{ "foo"},newClass[] { Integer.TYPE }));

    }});

    Object obj= e.create();

    比自己生成class要简单,但是,要学会它的API还是得花大量的时间,并且,上面的代码很难看懂对不对?

    有木有更简单的方法?

    有!

    换一个思路,如果我们能创建UserProxy.java这个源文件,再调用Java编译器,直接把源码编译成class,再加载进虚拟机,任务完成!

    毕竟,创建一个字符串格式的源码是很简单的事情,就是拼字符串嘛,高级点的做法可以用一个模版引擎。

    如何编译?

    Java的编译器是javac,但是,在很早很早的时候,Java的编译器就已经用纯Java重写了,自己能编译自己,行业黑话叫“自举”。从Java 1.6开始,编译器接口正式放到JDK的公开API中,于是,我们不需要创建新的进程来调用javac,而是直接使用编译器API来编译源码。

    使用起来也很简单:

    JavaCompiler compiler =ToolProvider.getSystemJavaCompiler();int compilationResult = compiler.run(null, null, null, '/path/to/Test.java');

    这么写编译是没啥问题,问题是我们在内存中创建了Java代码后,必须先写到文件,再编译,最后还要手动读取class文件内容并用一个ClassLoader加载。

    有木有更简单的方法?

    有!

    其实Java编译器根本不关心源码的内容是从哪来的,你给它一个String当作源码,它就可以输出byte[]作为class的内容。

    所以,我们需要参考Java Compiler API的文档,让Compiler直接在内存中完成编译,输出的class内容就是byte[]。

    代码改造如下:

    Mapresults;

    JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();

    StandardJavaFileManager stdManager= compiler.getStandardFileManager(null, null, null);try (MemoryJavaFileManager manager = newMemoryJavaFileManager(stdManager)) {

    JavaFileObject javaFileObject=manager.makeStringSource(fileName, source);

    CompilationTask task= compiler.getTask(null, manager, null, null, null, Arrays.asList(javaFileObject));if(task.call()) {

    results=manager.getClassBytes();

    }

    }

    上述代码的几个关键在于:

    用MemoryJavaFileManager替换JDK默认的StandardJavaFileManager,以便在编译器请求源码内容时,不是从文件读取,而是直接返回String;

    用MemoryOutputJavaFileObject替换JDK默认的SimpleJavaFileObject,以便在接收到编译器生成的byte[]内容时,不写入class文件,而是直接保存在内存中。

    最后,编译的结果放在Map中,Key是类名,对应的byte[]是class的二进制内容。

    为什么编译后不是一个byte[]呢?

    因为一个.java的源文件编译后可能有多个.class文件!只要包含了静态类、匿名类等,编译出的class肯定多于一个。

    如何加载编译后的class呢?

    加载class相对而言就容易多了,我们只需要创建一个ClassLoader,覆写findClass()方法:

    class MemoryClassLoader extendsURLClassLoader {

    Map classBytes = new HashMap();public MemoryClassLoader(MapclassBytes) {super(new URL[0], MemoryClassLoader.class.getClassLoader());this.classBytes.putAll(classBytes);

    }

    @Overrideprotected Class> findClass(String name) throwsClassNotFoundException {byte[] buf =classBytes.get(name);if (buf == null) {return super.findClass(name);

    }

    classBytes.remove(name);return defineClass(name, buf, 0, buf.length);

    }

    }

    除了写ORM用之外,还能干什么?

    可以用它来做一个Java脚本引擎。实际上本文的代码主要就是参考了Scripting项目的源码。

    完整的源码呢?

    也就200行代码吧!动态创建class不是梦!

    展开全文
  • 动态生成java类,来自bao110908大神

    千次阅读 2014-01-26 14:42:54
    动态生成java类,来自bao110908大神 分类: Java 2011-03-03 16:31 670人阅读 评论(0) 收藏 举报 javapropertiesobjectbeanmethodsstring Cglib 中有个 BeanGenerator 就是专门用于做这个的,可以动态生成 ...
    Cglib 中有个 BeanGenerator 就是专门用于做这个的,可以动态生成 JavaBean,
    BeanGenerator 利用了非常底层的 ASM 字节码框架来实现的。
    1. import java.lang.reflect.Field;  
    2. import java.lang.reflect.Method;  
    3. import java.util.HashMap;  
    4. import java.util.Iterator;  
    5. import java.util.Map;  
    6. import java.util.Set;  
    7.   
    8. import net.sf.cglib.beans.BeanGenerator;  
    9. import net.sf.cglib.beans.BeanMap;  
    10.   
    11. public class DynaBeanCglibTest {  
    12.   
    13.     public static void main(String[] args) throws ClassNotFoundException {  
    14.           
    15.         System.out.println("Generate JavaBean ...");          
    16.         // 设置类成员属性  
    17.         Map properties = new HashMap();  
    18.         properties.put("id", Class.forName("java.lang.Integer"));  
    19.         properties.put("name", Class.forName("java.lang.String"));  
    20.         properties.put("address", Class.forName("java.lang.String"));  
    21.         // 生成动态 Bean  
    22.         CglibDynaBean bean = new CglibDynaBean(properties);  
    23.         System.out.println("  OK!");  
    24.           
    25.         System.out.println("Set values ...");  
    26.         // 给 Bean 设置值  
    27.         bean.setValue("id"new Integer(123));  
    28.         bean.setValue("name""454");  
    29.         bean.setValue("address""789");  
    30.         System.out.println("  OK!");  
    31.           
    32.         System.out.println("Get values");  
    33.         // 从 Bean 中获取值,当然了获得值的类型是 Object  
    34.         System.out.println("  >> id      = " + bean.getValue("id"));  
    35.         System.out.println("  >> name    = " + bean.getValue("name"));  
    36.         System.out.println("  >> address = " + bean.getValue("address"));  
    37.   
    38.         System.out.println("Class name");  
    39.         // 查看动态 Bean 的类名  
    40.         Class clazz = bean.getObject().getClass();  
    41.         System.out.println("  >> " + clazz.getName());  
    42.           
    43.         System.out.println("Show all methods");  
    44.         // 查看动态 Bean 中声明的方法  
    45.         Method[] methods = clazz.getDeclaredMethods();  
    46.         for(int i = 0; i < methods.length; i++) {  
    47.             System.out.println("  >> " + methods[i].getName());  
    48.         }  
    49.   
    50.         System.out.println("Show all properties");  
    51.         // 查看动态 Bean 中声明的字段  
    52.         Field[] fields = clazz.getDeclaredFields();  
    53.         for(int i = 0; i < fields.length; i++) {  
    54.             System.out.println("  >> " + fields[i].getName());  
    55.         }   
    56.     }  
    57. }  
    58.   
    59. class CglibDynaBean {  
    60.     private Object object = null;  
    61.     private BeanMap beanMap = null;  
    62.       
    63.     public CglibDynaBean(Map properties) {          
    64.         this.object = generateBean(properties);  
    65.         this.beanMap = getBeanMap();  
    66.     }  
    67.       
    68.     public void setValue(String property, Object value) {  
    69.         beanMap.put(property, value);  
    70.     }  
    71.       
    72.     public Object getValue(String property) {  
    73.         return beanMap.get(property);  
    74.     }  
    75.   
    76.     public Object getObject() {  
    77.         return this.object;  
    78.     }    
    79.      
    80.     private Object generateBean(Map properties) {  
    81.         BeanGenerator generator = new BeanGenerator();  
    82.         Set keySet = properties.keySet();  
    83.         for(Iterator i = keySet.iterator(); i.hasNext();) {  
    84.             String key = (String)i.next();  
    85.             generator.addProperty(key, (Class)properties.get(key));  
    86.         }  
    87.         return generator.create();  
    88.     }  
    89.       
    90.     private BeanMap getBeanMap() {  
    91.         return BeanMap.create(this.object);  
    92.     }  

    展开全文
  • 动态生成java类与对象

    2020-07-15 19:50:35
    // 注解 表名 AnnotationsAttribute bodyAttr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag); Annotation bodyAnnot = new Annotation("org.springframework.data.mongodb.core....

    依赖

     <dependency>
                <groupId>org.javassist</groupId>
                <artifactId>javassist</artifactId>
                <version>3.25.0-GA</version>
    </dependency>
    

    代码

    import javassist.*;
    import javassist.bytecode.AnnotationsAttribute;
    import javassist.bytecode.ClassFile;
    import javassist.bytecode.ConstPool;
    import javassist.bytecode.annotation.Annotation;
    import javassist.bytecode.annotation.StringMemberValue;
    import org.springframework.beans.factory.BeanCreationException;
    import org.springframework.util.ReflectionUtils;
    
    import java.util.List;
    import java.util.Map;
    import java.util.UUID;
    
    public class DynamicObjectUtils {
        /**
         * 生成class
         * @param className
         * @param fields
         * @return
         * @throws CannotCompileException
         */
        public static Class<?> prepareClass(final String className, List<String> fields) throws CannotCompileException {
            ClassPool pool = ClassPool.getDefault();
            CtClass evalClass = pool.makeClass(className + UUID.randomUUID().toString());
            for ( String field : fields) {
                CtField ctField = CtField.make("public java.lang.String " + field + ";", evalClass);
                evalClass.addField(ctField);
                evalClass.addMethod(CtNewMethod.getter("get" + capitalize(field), ctField));
                evalClass.addMethod(CtNewMethod.setter("set" + capitalize(field), ctField));
            }
    
            ClassFile ccFile = evalClass.getClassFile();
            ConstPool constPool = ccFile.getConstPool();
    
            // 类注解 表名
            AnnotationsAttribute bodyAttr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
            Annotation bodyAnnot = new Annotation("org.springframework.data.mongodb.core.mapping.Document", constPool);
            bodyAnnot.addMemberValue("collection", new StringMemberValue(className, constPool));
            bodyAttr.addAnnotation(bodyAnnot);
    
            ccFile.addAttribute(bodyAttr);
    
            return evalClass.toClass();
        }
    
        /**
         * get set 方法名
         * @param field
         * @return
         */
        private static String capitalize(String field) {
            field = field.substring(0, 1).toUpperCase() + field.substring(1);
            return  field;
        }
    
        /**
         * 生成实例
         * @param clazz
         * @param fields
         * @param values
         * @return
         */
        public static Object createObject(Class<?> clazz, List<String> fields, Map<String, Object> values) {
            try {
                Object obj = clazz.newInstance();
                for (String field : fields) {
                    ReflectionUtils.setField(clazz.getField(field), obj, values.get(field));
                }
                return obj;
            } catch (Exception e) {
                return new BeanCreationException(String.format("class name: %s", clazz));
            }
        }
    
    }
    
    
    展开全文
  • 考虑这种情况:我有一个名为person.xml的XML文件,其中包含以下数据.MrFoo28如果我想将这个XML读入Java对象,我将创建一个名为PersonBean的Java bean(使用属性的getter / setter):class Person{String name;...
  • 生成源码文件 -> 编译源码 -> 加载 方式1:javac编译 可以用 ProcessBuilder 这个启动 javac 进程,编译源码文件 方式2:Java Compiler API 编译 JDK中的 Java Compiler API 提供了与 javac 对等的...
  • 启动加载器(Bootstrap Class-Loader),加载 jre/lib 下面的 jar 文件,如 rt.jar。 修改核心类库可以使用下面的命令: # 指定新的 bootclasspath,替换 java.* 包的内部实现 java -Xbootclasspath:<your_boot...
  • 有三种方式根据配置文件生成JAVA类:   第一: 是我们自己实现一个工具,手工调用来根据配置文件生成Java源代码,这种方式就是代码生成器之类的工具。 这种方式的好处是可以在开发过程中生成类文件,然后在...
  • 如何动态生成一个Java类开发者编写Java 代码,调用 javac 编译生成 class 文件。然后通过类加载机制载入 JVM ,即成为了应用可以使用的 Java 类。可以写一个编译类编译 java 代码:import java.io.File; import java....
  • 我们可以从常见的 Java ...从上面过程得到启发,其中一个直接的方式是从源码入手,可以利用 Java 程序生成一段源码, 然后保存到文件等,下面就只需要解决编译问题了。有一种笨办法,直接用 ProcessBuilder 之...
  • import java.io.*;//定制的装入器public class TestCompile extends ClassLoader{String _compiler;String _classpath;public static void main(String[] args){new TestCompile();}public Tes...
  • 需要的可以直接拿走但是我有个问题 就是下面代码得枚举是连个参数的 可我的是5个参数得 我知道makeEnum和addEnum两个方法需要改一下 但是没看懂不知道怎么改 请大佬帮着看看指点指点import java.lang.reflect....
  • 如何动态生成一个Java类 开发者编写Java 代码,调用 javac 编译生成 class 文件。然后通过类加载机制载入 JVM ,即成为了应用可以使用的 Java 类。 可以写一个编译类编译 java 代码: import java.io.File; import ...
  • 所以想到将公共逻辑写到父类实现,将特定逻辑根据字符串动态生成处理。这就可以一劳永逸解决这个问题。那就着手从Java如何根据字符串模板在运行时动态生成对象。Java是一门静态语言,通常,我们需要...
  • 前言,本次记录重点在读取数据库表结构,及解析转换成java实体需要字段。 主要包含,表 列名、类型、注释的读取解析 至于代码生成,可以基于已有的代码生成模板 整合进去即可 pom: <!-- Mysql Connector ...
  • 最近在实现一个功能需要动态自动Java类,刚好了解了一下java buddy这个库。Java buddy是基于ASM实现,所以比ASM好用的多。还有一个名气更大的库mockito,其核心就是基于byte buddy实现的,可以动态生成mock类,非常...
  • ​通过Map动态生成JavaBean ,生成的JavaBean只有对应属性的get,set方法。工具package com.fongtech.cli.common.util;import org.springframework.cglib.beans.BeanGenerator;import org.springframework.cglib....
  • package ...import java.beans.BeanInfo;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.io.InputStream;import java.lang.reflect.Method;i...
  • 定义了一个DataTester的接口,这个接口的test函数接受一个TestData的实例,然后...这里主要用了2个工具,一个是com.github.javaparser.ast下面的各种工具,用来动态生成一棵语法树,然后用这棵语法树来生成代码...
  • packagecom.java.test.dynamicpojo;importjava.io.ByteArrayOutputStream;importjava.io.IOException;importjava.io.OutputStream;importjava.lang.reflect.Method;importjava.net.URI;importjava.util.Arrays;impor...
  • javapoet动态生成java代码

    千次阅读 2018-05-23 10:28:51
    刚接触第一感觉 动态生成java代码???java代码不就是一个后缀名为.java的txt文档吗?仔细想了下,如果要生成这样的代码的确挺麻烦,你要考虑导包的问题,以及复杂的语法javapoet代码仓库地址其实git地址官方介绍的demo写...
  • java动态生成类

    千次阅读 2017-07-29 15:45:37
    有个技术实现需求:动态生成类,其中中的属性来自参数对象中的全部属性以及来自参数对象propertities文件。 那么技术实现支持:使用cglib代理。 具体的实现步骤: 1.cglib的jar包(cglib-nodep):我用的是...
  • 所以想到将公共逻辑写到父类实现,将特定逻辑根据字符串动态生成处理。这就可以一劳永逸解决这个问题。那就着手从Java如何根据字符串模板在运行时动态生成对象。Java是一门静态语言,通常,我们需要...
  • JAVA 动态生成实体.rar

    热门讨论 2009-12-13 20:01:21
    JAVA 动态生成实体.rar mvc做的,指需要输入数据库名 密码 数据库的名字即可
  • package ...import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.OutputStream;import java.lang.reflect.Method;import java.net.URI;import java.util.Array...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,749
精华内容 3,099
关键字:

动态生成java类

java 订阅