У меня возникает следующая ошибка при создании 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 IЯ использую Vaadin для представления схемы таблиц 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());
}
}
Извините за некрасивый код, но это только минимальная версия.
Может ли кто-нибудь дать какое-нибудь руководство по решению этой проблемы?