This is the 23rd day of my participation in the August More Text Challenge.More challenges in August

The previous article introduced the method of creating Java beans using Cglib. Although Java beans are created dynamically, there is a problem that the field name in the Java bean is not quite what we expected

Let’s look at a way to create dynamic classes directly by stitching Together Java code, then compiling it into a class and loading it

1. Java code dynamic compilation and creation

Next we mainly use the JDK’s own JavaCompiler to achieve Java source code compilation, generation class, and then by ClassLoader to load the class

If we now have a Java file and want to dynamically compile and load the class while the project is running, the general process is as follows

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int compilationResult = compiler.run(null.null.null.'/path/Test.java');
Copy the code

Rather than existing Java files, our scenario is to create Java classes based on the Java source code for String

Tests need to be extended against the above logic; If you don’t want to worry about the details, just use the open source tripartite package

<dependency>
    <groupId>com.itranswarp</groupId>
    <artifactId>compiler</artifactId>
    <version>1.0</version>
</dependency>
Copy the code

Let’s also implement a way to generate Java beans based on a Map

Based on javacode to generate source code

/** * Compile the Java code and generate the object **@paramPackageName package name *@paramClassName the name of the class@paramJavaCode source *@return
 * @throws Exception
 */
public Object createBean(String packageName, String className, String javaCode) throws Exception {
    JavaStringCompiler compiler = new JavaStringCompiler();
    Map<String, byte[]> result = compiler.compile(className + ".java"."package " + packageName + "; \n" + javaCode);
    Class clz = compiler.loadClass(packageName + "." + className, result);
    return clz.newInstance();
}
Copy the code

The next thing we need to implement is to generate the corresponding Java code based on the map

private String genCode(String clzName, Map<String, Object> map) {
    StringBuilder builder = new StringBuilder("public class ").append(clzName).append("{\n");
    for (Map.Entry<String, Object> obj: map.entrySet()) {
        String fieldType;
        if (obj.getValue() instanceof List) {
            fieldType = "java.util.List";
        } else if (obj.getValue() instanceof Set) {
            fieldType = "java.util.Set";
        } else if (obj.getValue() instanceof  Map) {
            fieldType = "java.util.Map";
        } else {
            fieldType = obj.getValue().getClass().getName().replace("$".".");
        }
        builder.append("\tpublic ").append(fieldType).append("").append(obj.getKey()).append("; \n");
    }
    builder.append("}");
    return builder.toString();
}
Copy the code

Note that the above implementation is only the most basic implementation. Note that if value is an inner class, there may be a pit (for example, the above special treatment for container classes).

One last test

@Test
public void testGenMapBean(a) throws Exception {
    Map<String, Object> map = new HashMap<>();
    map.put("hello"."world");
    map.put("key".12);
    map.put("list", Arrays.asList(1.2.3));

    String packageName = "com.git.hui.dynamic";
    String clzName = "MBean1";
    String code = genCode(clzName, map);
    Object bean = createBean(packageName, clzName, code);
    // Initialize the member of the bean
    for(Map.Entry<String, Object> entry: map.entrySet()) {
        Field field = bean.getClass().getField(entry.getKey());
        field.set(bean, entry.getValue());
    }
    System.out.println("---------------- java code ---------------\n" + code + "\n------------------");
    System.out.println(JSON.toJSONString(bean));
}
Copy the code

An example of generating a bean object from a Map and initializing the member values is given above

The output is as follows

---------------- java code --------------- public class MBean1{ public java.lang.String hello; public java.util.List list; public java.lang.Integer key; } -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- {" hello ", "world", "key" : 12, "a list" : [1, 2, 3]}Copy the code

The output is as expected, directly by assembling Java code and then generating objects

So where does this apply?

  • For example, I made a framework for dynamic script execution. You can write Java code on the console, and then hand it to the framework to run. Of course, this might be a more elegant choice for scripting in Groovy

II. The other

1. A gray Blog:liuyueyi.github.io/hexblog

A gray personal blog, recording all the study and work in the blog, welcome everyone to go to stroll

2. Statement

As far as the letter is not as good, the above content is purely one’s opinion, due to the limited personal ability, it is inevitable that there are omissions and mistakes, if you find bugs or have better suggestions, welcome criticism and correction, don’t hesitate to appreciate

  • Micro Blog address: Small Gray Blog
  • QQ: a gray /3302797840
  • Wechat official account: One Grey Blog