JPA: Как указать имя таблицы, соответствующее классу во время выполнения?
Вы можете указать имя таблицы jre во время загрузки с помощью jpa настраиваемого ClassLoader, который jpa перезаписывает аннотацию jpa @Table
для классов по мере их загрузки. На java-libraries данный момент я не уверен oraclejdk на 100%, как вы можете гарантировать, что .java Hibernate загружает свои javax классы через этот ClassLoader.
Классы jre переписываются с использованием javax the ASM bytecode framework.
Предупреждение. Эти классы являются экспериментальными.
public class TableClassLoader extends ClassLoader {
private final Map tablesByClassName;
public TableClassLoader(Map tablesByClassName) {
super();
this.tablesByClassName = tablesByClassName;
}
public TableClassLoader(Map tablesByClassName, ClassLoader parent) {
super(parent);
this.tablesByClassName = tablesByClassName;
}
@Override
public Class> loadClass(String name) throws ClassNotFoundException {
if (tablesByClassName.containsKey(name)) {
String table = tablesByClassName.get(name);
return loadCustomizedClass(name, table);
} else {
return super.loadClass(name);
}
}
public Class> loadCustomizedClass(String className, String table) throws ClassNotFoundException {
try {
String resourceName = getResourceName(className);
InputStream inputStream = super.getResourceAsStream(resourceName);
ClassReader classReader = new ClassReader(inputStream);
ClassWriter classWriter = new ClassWriter(0);
classReader.accept(new TableClassVisitor(classWriter, table), 0);
byte[] classByteArray = classWriter.toByteArray();
return super.defineClass(className, classByteArray, 0, classByteArray.length);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private String getResourceName(String className) {
Type type = Type.getObjectType(className);
String internalName = type.getInternalName();
return internalName.replaceAll("\\.", "/") + ".class";
}
}
TableClassLoader
использует java TableClassVisitor
для перехвата вызовов метода core-java visitAnnotation:
public class TableClassVisitor extends ClassAdapter {
private static final String tableDesc = Type.getDescriptor(Table.class);
private final String table;
public TableClassVisitor(ClassVisitor visitor, String table) {
super(visitor);
this.table = table;
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor annotationVisitor;
if (desc.equals(tableDesc)) {
annotationVisitor = new TableAnnotationVisitor(super.visitAnnotation(desc, visible), table);
} else {
annotationVisitor = super.visitAnnotation(desc, visible);
}
return annotationVisitor;
}
}
TableAnnotationVisitor
в конечном итоге отвечает openjdk за изменение поля name
аннотации jakarta-persistence @Table
:
public class TableAnnotationVisitor extends AnnotationAdapter {
public final String table;
public TableAnnotationVisitor(AnnotationVisitor visitor, String table) {
super(visitor);
this.table = table;
}
@Override
public void visit(String name, Object value) {
if (name.equals("name")) {
super.visit(name, table);
} else {
super.visit(name, value);
}
}
}
Поскольку мне не удалось java-api найти класс AnnotationAdapter
в библиотеке java ASM, вот один, который я java сделал сам:
public class AnnotationAdapter implements AnnotationVisitor {
private final AnnotationVisitor visitor;
public AnnotationAdapter(AnnotationVisitor visitor) {
this.visitor = visitor;
}
@Override
public void visit(String name, Object value) {
visitor.visit(name, value);
}
@Override
public AnnotationVisitor visitAnnotation(String name, String desc) {
return visitor.visitAnnotation(name, desc);
}
@Override
public AnnotationVisitor visitArray(String name) {
return visitor.visitArray(name);
}
@Override
public void visitEnd() {
visitor.visitEnd();
}
@Override
public void visitEnum(String name, String desc, String value) {
visitor.visitEnum(name, desc, value);
}
}
java
hibernate
jpa
JPA: Как указать имя таблицы, соответствующее классу во время выполнения?
Мы используем файлы cookies для улучшения работы сайта. Оставаясь на нашем сайте, вы соглашаетесь с условиями использования файлов cookies. Чтобы ознакомиться с нашими Положениями о конфиденциальности и об использовании файлов cookie, нажмите здесь.