Open cilfm opened 3 weeks ago
This is not possible with injection as the class loader cannot be patched to resolve the class file. You could use ClassLoadingStrategy.Default.WRAPPER_PERSISTENT
instead.
Alternatively, you can use an AgentBuilder
and trigger a retransformation where the JVM will resolve the class file.
This is not possible with injection as the class loader cannot be patched to resolve the class file. You could use
ClassLoadingStrategy.Default.WRAPPER_PERSISTENT
instead.Alternatively, you can use an
AgentBuilder
and trigger a retransformation where the JVM will resolve the class file.
Hello, I used ClassLoadingStrategy.Default.WRAPPER_PERSISTENT
to load the class when creating it, but encountered an error when using this class:
Caused by: java.lang.ClassNotFoundException: com.pf.test.entity.TestEntity
at net.bytebuddy.dynamic.loading.ByteArrayClassLoader.findClass(ByteArrayClassLoader.java:396) ~[byte-buddy-1.11.22.jar:na]
at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[na:1.8.0_271]
at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_271]
at java.lang.Class.forName0(Native Method) ~[na:1.8.0_271]
at java.lang.Class.forName(Class.java:348) ~[na:1.8.0_271]
at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:114) ~[na:1.8.0_271]
... 128 common frames omitted
Testing has found that Class.forName("com.pf.test.entity.TestEntity", false, this.getClass().getClassLoader())
will all report ClassNotFoundException,when Load class by .load(this.getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER_PERSISTENT)
How should I solve it?
Is this the class that you defined? That should not happen. Can you try to create a reproducer? Likely there is a mixup somewhere.
Is this the class that you defined? That should not happen. Can you try to create a reproducer? Likely there is a mixup somewhere.
Yes, that class was defined by me. Sorry, I don't understand how to create a reproducer. I put my code below, can you help me?
package com.pf.test;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
public class ByteBuddyTest {
public static void main(String[] args) {
Class<?> entity = createEntity();
System.out.println("entity class is created");
Class<?> service = createService(entity);
System.out.println("service interface is created");
Class<?> mapper = createMapper(entity);
System.out.println("mapper interface is created");
createServiceImpl(mapper, entity, service);
System.out.println("serviceImpl class is created");
}
private static Class<?> createEntity() {
return new ByteBuddy().subclass(Object.class).name("com.pf.test.entity.TestEntity")
.annotateType(AnnotationDescription.Builder.ofType(TableName.class).define("value", "test").build())
.defineProperty("name", String.class).defineProperty("cityCode", String.class)
.defineProperty("cityLevel", Integer.class).make()
.load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.WRAPPER_PERSISTENT).getLoaded();
}
private static Class<?> createService(Class<?> entityClass) {
return new ByteBuddy()
.makeInterface(TypeDescription.Generic.Builder.parameterizedType(IService.class, entityClass).build())
.name("com.pf.test.service.ITbDicService")
.defineMethod("testMethod",
TypeDescription.Generic.Builder
.parameterizedType(TypeDescription.ForLoadedType.of(List.class),
TypeDescription.Generic.Builder
.parameterizedType(Map.class, String.class, Object.class).build())
.build(),
Visibility.PUBLIC)
.withParameter(TypeDescription.Generic.Builder.parameterizedType(Map.class, String.class, Object.class)
.build())
.withoutCode().make()
.load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.WRAPPER_PERSISTENT).getLoaded();
}
private static Class<?> createMapper(Class<?> entityClass) {
return new ByteBuddy()
.makeInterface(TypeDescription.Generic.Builder.parameterizedType(BaseMapper.class, entityClass).build())
.name("com.pf.test.mapper.TbDicMapper")
.annotateType(AnnotationDescription.Builder.ofType(Mapper.class).build())
.defineMethod("testMethod",
TypeDescription.Generic.Builder
.parameterizedType(TypeDescription.ForLoadedType.of(List.class),
TypeDescription.Generic.Builder
.parameterizedType(Map.class, String.class, Object.class).build())
.build(),
Visibility.PUBLIC)
.withParameter(TypeDescription.Generic.Builder.parameterizedType(Map.class, String.class, Object.class)
.build())
.annotateParameter(AnnotationDescription.Builder.ofType(Param.class).define("value", "querys").build())
.withoutCode()
.annotateMethod(AnnotationDescription.Builder.ofType(Select.class)
.defineArray("value", new String[] { "select * from test" }).build())
.make().load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.WRAPPER_PERSISTENT)
.getLoaded();
}
private static Class<?> createServiceImpl(Class<?> mapperClass, Class<?> entityClass, Class<?> serviceClass) {
return new ByteBuddy()
.subclass(TypeDescription.Generic.Builder.parameterizedType(ServiceImpl.class, mapperClass, entityClass)
.build())
.implement(serviceClass).name("com.pf.test.service.impl.TbDicServiceImpl")
.annotateType(AnnotationDescription.Builder.ofType(Service.class).build())
.method(ElementMatchers.named("testMethod")).intercept(MethodDelegation.toField("baseMapper")).make()
.load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.WRAPPER_PERSISTENT).getLoaded();
}
}
Here is the output content
entity class is created
service interface is created
mapper interface is created
Exception in thread "main" java.lang.TypeNotPresentException: Type com.pf.test.entity.TestEntity not present
at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:117)
at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:125)
at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49)
at sun.reflect.generics.visitor.Reifier.reifyTypeArguments(Reifier.java:68)
at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:138)
at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49)
at sun.reflect.generics.repository.ClassRepository.getSuperInterfaces(ClassRepository.java:108)
at java.lang.Class.getGenericInterfaces(Class.java:913)
at net.bytebuddy.description.type.TypeList$Generic$OfLoadedInterfaceTypes$TypeProjection.resolve(TypeList.java:823)
at net.bytebuddy.description.type.TypeDescription$Generic$LazyProjection.accept(TypeDescription.java:6301)
at net.bytebuddy.description.type.TypeDescription$Generic$LazyProjection$WithResolvedErasure.resolve(TypeDescription.java:6953)
at net.bytebuddy.description.type.TypeDescription$Generic$LazyProjection.accept(TypeDescription.java:6301)
at net.bytebuddy.dynamic.scaffold.MethodGraph$Compiler$Default.doAnalyze(MethodGraph.java:746)
at net.bytebuddy.dynamic.scaffold.MethodGraph$Compiler$Default.analyze(MethodGraph.java:710)
at net.bytebuddy.dynamic.scaffold.MethodGraph$Compiler$Default.doAnalyze(MethodGraph.java:746)
at net.bytebuddy.dynamic.scaffold.MethodGraph$Compiler$Default.compile(MethodGraph.java:668)
at net.bytebuddy.dynamic.scaffold.MethodGraph$Compiler$AbstractBase.compile(MethodGraph.java:519)
at net.bytebuddy.dynamic.scaffold.MethodRegistry$Default.prepare(MethodRegistry.java:472)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.toTypeWriter(SubclassDynamicTypeBuilder.java:212)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.toTypeWriter(SubclassDynamicTypeBuilder.java:203)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$UsingTypeWriter.make(DynamicType.java:4055)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3739)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:3991)
at com.aecc.plugins.ByteBuddyTest.createServiceImpl(ByteBuddyTest.java:90)
at com.aecc.plugins.ByteBuddyTest.main(ByteBuddyTest.java:33)
Caused by: java.lang.ClassNotFoundException: com.pf.test.entity.TestEntity
at net.bytebuddy.dynamic.loading.ByteArrayClassLoader.findClass(ByteArrayClassLoader.java:404)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:114)
... 24 more
Project dependencies
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.14.19</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>1.14.19</version>
</dependency>
The problem is that you create wrappers that all sit on top of the system class loader. The generated classes will be visible only within their own loader and children. So you will have to present any generated class's class loader to the next generation.
To avoid generating so many class loaders, you can choose to not seal them. Have a look at ClassLoadingStrategy for this. Ideally, you should seal the loader after you generated all classes.
byte-buddy version:1.14.19
Firstly, I have successfully dynamically defined a class
com.pf.test.entity.TestEntity
Now I want to add another property to this class
bug I get the following exception