创建POJO时出现以下错误:
java.lang.RuntimeException: act_ge_bytearray: frozen class (cannot edit)
at javassist.ClassPool.checkNotFrozen(ClassPool.java:587) ~[javassist-3.25.0-GA.jar:na]
at javassist.ClassPool.makeClass(ClassPool.java:829) ~[javassist-3.25.0-GA.jar:na]
at javassist.ClassPool.makeClass(ClassPool.java:806) ~[javassist-3.25.0-GA.jar:na]
我通过以下方式创建POJO:
Class<?> clazz = null;
try {
clazz = PojoGenerator.generate( "net.javaforge.blog.javassist.Pojo$Generated", props);
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
}
在选择特定表后将创建对象。初次尝试有效,但其他失败。
例如,在选择对象foo
之后的首次尝试中,POJO创建得很好,但是在选择其他项之后出现了问题。
编辑
我已根据以下教程创建了POJO生成器类: https://blog.javaforge.net/post/31913732423/howto-create-java-pojo-at-runtime-with-javassist
编辑2 我正在使用Vaadin表示Web应用程序中PostgreSQL表的架构。
以下代码获取所选表的每一列,并为给定名称创建properties
,getters
和setters
。然后我要在所选表中创建尽可能多的记录
package pl.registers.spring.view;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import javassist.CannotCompileException;
import javassist.NotFoundException;
import pl.registers.spring.service.DbService;
import pl.registers.spring.test.DatabaseTableModel;
import pojo.PojoGenerator;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Route("")
public class TablesView extends VerticalLayout {
private List<String> tables;
public TablesView() {
Connection con=null;
try {
con = DriverManager.getConnection("jdbc:postgresql://localhost:5432/process-engine", "postgres",
"postgres");
} catch (SQLException e) {
e.printStackTrace();
}
ComboBox tablesCombo = new ComboBox();
try {
tables = DbService.getInstance().getTableNames(con);
} catch (SQLException e) {
e.printStackTrace();
}
Map<String, Class<?>> props = new HashMap<String, Class<?>>();
List items = new ArrayList();
Grid grid = new Grid();
try {
tablesCombo.setItems(DbService.getInstance().getTableNames(con));
} catch (SQLException e) {
e.printStackTrace();
}
tablesCombo.addValueChangeListener(table -> {
items.clear();
try {
DatabaseTableModel dP = new DatabaseTableModel(DriverManager.getConnection("jdbc:postgresql://localhost:5432/process-engine", "postgres",
"postgres"), table.getValue());
//get column names
for(int i = 0; i < dP.getColumnCount(); i++) {
props.put(dP.getColumnName(i), String.class);
}
//get records
System.out.println("data vector: " + dP.getDataVector());
//generate Class schema
Class<?> clazz = null;
try {
clazz = PojoGenerator.generate(
"net.javaforge.blog.javassist.Pojo$Generated", props);
// table.getValue().toString(), props);
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
}
//create as many objects as many records
try {
for(int i = 0; i < dP.getDataVector().size(); i++) {
items.add(clazz.newInstance());
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
List dataVectorCastedToList = dP.getDataVector();
//set objects values
for(int i = 0; i <= items.size()-1; i++) {
try {
clazz.getMethod("Constructor", java.util.List.class).invoke(items.get(i), dataVectorCastedToList.get(i));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
List<String> getters = new ArrayList<>();
//get methods
for(int i = 0; i < clazz.getMethods().length-1; i++){
String methodName = clazz.getMethods()[i].getName();
if(methodName.contains("get")) {
getters.add(methodName);
}
}
//remove getClass method
if(getters.contains("getClass"))
getters.remove("getClass");
System.out.println("getters" + getters);
grid.setItems(items);
//set columns
getters.forEach(item -> {
grid.addColumn(column -> {
try {
return
column.getClass().getMethod(item).invoke(column);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}).setHeader(item);
});
} catch (SQLException e) {
e.printStackTrace();
}
});
//add to layout
add(tablesCombo, grid);
}
}
我还在generateInitMethod
类中创建了自己的PojoGenerator
方法,该方法为创建的对象设置数据。 PojoGenerator
的样子如下:
package pojo;
import javassist.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class PojoGenerator {
public static Class generate(String className, Map<String, Class<?>> properties) throws NotFoundException, CannotCompileException {
CtClass cc;
System.out.println("properties passed to pojo generator: " + properties);
ClassPool pool = ClassPool.getDefault();
cc = pool.makeClass(className);
System.out.println("is frozen " + cc.isFrozen());
cc.debugWriteFile();
// add this to define a super class to extend
// cc.setSuperclass(resolveCtClass(MySuperClass.class));
// add this to define an interface to implement
cc.addInterface(resolveCtClass(Serializable.class));
for (Map.Entry<String, Class<?>> entry : properties.entrySet()) {
cc.addField(new CtField(resolveCtClass(entry.getValue()), entry.getKey(), cc));
// add getter
cc.addMethod(generateGetter(cc, entry.getKey(), entry.getValue()));
// add setter
cc.addMethod(generateSetter(cc, entry.getKey(), entry.getValue()));
}
cc.addMethod(generateInitMethod(cc, properties));
return cc.toClass();
}
private static CtMethod generateGetter(CtClass declaringClass, String fieldName, Class fieldClass)
throws CannotCompileException {
String getterName = "get" + fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
StringBuffer sb = new StringBuffer();
sb.append("public ").append(fieldClass.getName()).append(" ")
.append(getterName).append("(){").append("return this.")
.append(fieldName).append(";").append("}");
return CtMethod.make(sb.toString(), declaringClass);
}
private static CtMethod generateSetter(CtClass declaringClass, String fieldName, Class fieldClass)
throws CannotCompileException {
String setterName = "set" + fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
StringBuffer sb = new StringBuffer();
sb.append("public void ").append(setterName).append("(")
.append(fieldClass.getName()).append(" ").append(fieldName)
.append(")").append("{").append("this.").append(fieldName)
.append("=").append(fieldName).append(";").append("}");
return CtMethod.make(sb.toString(), declaringClass);
}
private static CtMethod generateInitMethod(CtClass declaringClass, Map<String, Class<?>> properties)
throws CannotCompileException {
String setterName = "Constructor";
List<String> fields = new ArrayList<>();
//set attributes names
properties.forEach((e, v) -> {
fields.add(e);
});
String body = "";
for (int i = 0; i < fields.size(); i++) {
body += "this.".concat(fields.get(i)).concat("=").concat("(String)arguments.get(").concat(String.valueOf(i)).concat(")").concat(";");
}
StringBuffer sb = new StringBuffer();
sb.append("public void ").append(setterName).append("(").append("java.util.List arguments").append(")")
.append("{")
.append(body)
.append("}");
System.out.println(sb);
return CtMethod.make(sb.toString(), declaringClass);
}
private static CtClass resolveCtClass(Class clazz) throws NotFoundException {
ClassPool pool = ClassPool.getDefault();
return pool.get(clazz.getName());
}
}
很抱歉难看的代码,但只有最低版本。
任何人都可以提供有关如何解决此问题的指导吗?
答案 0 :(得分:0)
实际上,这是Javassist库所做的检查,因为Java中的类名和包不能相同:
Class<?> clazz = PojoGenerator.generate( "net.javaforge.blog.javassist.Pojo$Generated", props);
Class<?> clazz2 = PojoGenerator.generate( "net.javaforge.blog.javassist.Pojo$Generated", props);
上面的将失败,因为第一条语句已经生成了Pojo
类。在命名第二个类Pojo2
时,以下代码将起作用:
Class<?> clazz = PojoGenerator.generate( "net.javaforge.blog.javassist.Pojo$Generated", props);
Class<?> clazz2 = PojoGenerator.generate( "net.javaforge.blog.javassist.Pojo2$Generated", props);
我从您的完整示例中看到,这是通过某些外部调用动态生成的,因此,为了解决该问题,您可能会找到一种存储表生成结果(即本地地图)并调用generate的方法。仅在缺少此内容时。就像这样:
Map<String, Class<?>> cache = new HashMap<String, Class<?>>();
...
Class<?> clazz = null;
try {
if (cache.containsKey("your.package.yourTableName$Generated")) {
clazz = cache.get("your.package.yourTableName$Generated");
} else {
clazz = PojoGenerator.generate( "your.package.yourTableName$Generated", props);
cache.put("your.package.yourTableName$Generated", clazz);
}
}...