不能注入已加载的类型



我想使用bytebuddy库向Author类添加一些变量。第二次调用apply方法后显示给我的问题是

线程"main"java.lang.IllegalStateException: Cannot inject already loaded type: class pl.edu. testosterone .entity. author

我不知道如何解决这个问题,我知道这可能是关于classLoader

package pl.edu.wat.testowy.reflection;
package pl.edu.wat.testowy.reflection;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.MethodCall;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.pool.TypePool;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class Reflection {
private TypeDescription entityDefinition;
private TypeDescription requestDefinition;
private TypeDescription responseDefinition;
private TypeDescription mapperDefinition;
private TypePool typePool;
private ByteBuddy byteBuddy;
public Reflection() {
this.typePool = TypePool.Default.ofSystemLoader();
this.byteBuddy = new ByteBuddy();
this.entityDefinition = typePool.describe("pl.edu.wat.testowy.entity.Author").resolve();
this.requestDefinition = typePool.describe("pl.edu.wat.testowy.dto.AuthorRequest").resolve();
this.responseDefinition = typePool.describe("pl.edu.wat.testowy.dto.AuthorResponse").resolve();
this.mapperDefinition = typePool.describe("pl.edu.wat.testowy.mapper.AuthorMapper").resolve();
}

FieldInformation fieldInformation = new FieldInformation();
FieldInformation2 fieldInformation2 = new FieldInformation2();

//nie beda to pola final bo one beda sie zmienialy
public static void apply(String test){
var ref = new Reflection();
ref.applyEntity(test);
ref.applyRequest(test);
ref.applyResponse(test);
ref.applyAuthorMapper(test);
}
public List<String> getFieldNames() {
FieldInformation2.readJson("fields2.json");
List<FieldInformation2> fields = FieldInformation2.getFields();
List<String> fieldNames = new ArrayList<>();
fields.forEach(f -> fieldNames.add(f.getFieldName()));
return fieldNames;
}
private void applyAuthorMapper(String test) {//musimy wyciagnac mappera
DynamicType.Builder <Object> builder = byteBuddy
.redefine(mapperDefinition,
ClassFileLocator.ForClassLoader.ofSystemLoader())
.method(named("fillAuthorRequest"))
.intercept(MethodCall.invoke(setterAuthorEntity(test))
.onArgument(0)
.withMethodCall(MethodCall
.invoke(getterRequest(test))
.onArgument(1)))
.method(named("fillAuthor"))
.intercept(MethodCall.invoke(setterAuthorResponse(test))
.onArgument(0)
.withMethodCall(MethodCall
.invoke(getterEntity(test))
.onArgument(1)));
try(var unloadedAuthor = builder.make()){
mapperDefinition = unloadedAuthor.load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.getTypeDescription();
} catch(IOException e){
throw new RuntimeException();
}
}
private MethodDescription getterEntity(String test){
return  entityDefinition
.getDeclaredMethods()
.filter(ElementMatchers.isGetter(test))
.stream()
.findFirst()
.orElseThrow();
}
private MethodDescription setterAuthorResponse(String test) {
return  responseDefinition
.getDeclaredMethods()
.filter(ElementMatchers.isSetter(test))
.stream()
.findFirst()
.orElseThrow();
}
private MethodDescription getterRequest(String test) {
return  requestDefinition
.getDeclaredMethods()
.filter(ElementMatchers.isGetter(test))
.stream()
.findFirst()
.orElseThrow();
}
private MethodDescription setterAuthorEntity(String test) {
return  entityDefinition
.getDeclaredMethods()
.filter(ElementMatchers.isSetter(test))
.stream()
.findFirst()
.orElseThrow();
}
private void applyResponse(String test) {
DynamicType.Builder <Object> builder = byteBuddy
.redefine(responseDefinition,
ClassFileLocator.ForClassLoader.ofSystemLoader())
.defineProperty(test,typePool.describe("java.lang.String").resolve());
try(var unloadedAuthor = builder.make()){
responseDefinition = unloadedAuthor.load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.getTypeDescription();

} catch(IOException e){
throw new RuntimeException();
}
}
private void applyRequest(String test) {
DynamicType.Builder <Object> builder = byteBuddy
.redefine(requestDefinition,
ClassFileLocator.ForClassLoader.ofSystemLoader())
.defineProperty(test,typePool.describe("java.lang.String").resolve());
try(var unloadedAuthor = builder.make()){
requestDefinition = unloadedAuthor.load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.getTypeDescription();

} catch(IOException e){
throw new RuntimeException();
}
}
public void applyEntity(String test) {
DynamicType.Builder <Object> builder = byteBuddy
.redefine(entityDefinition,
ClassFileLocator.ForClassLoader.ofSystemLoader())
.defineProperty(test,typePool.describe("java.lang.String").resolve());
try(var unloadedAuthor = builder.make()){
entityDefinition = unloadedAuthor.load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.getTypeDescription();
} catch(IOException e){
throw new RuntimeException();
}
}

}

package pl.edu.wat.testowy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import pl.edu.wat.testowy.reflection.Reflection;

@SpringBootApplication
public class TestowyApplication {
public static void main(String[] args) {
//tak jak tu korzystam z mechanizmu refleksji tak wystarczy utworzyc zalozmy 10 obiektow, gdzie podajemy nazwe i typ zmiennej
Reflection.apply("test");
Reflection.apply("test2");
SpringApplication.run(TestowyApplication.class, args);
}
}

我已经尝试修改classLoader,但无济于事,不太确定如何。

理想情况下应该添加缓存层,因为具有相同名称的类型只能存在一次。Byte Buddy为此提供了一个TypeCache类。

最新更新