-
-
Notifications
You must be signed in to change notification settings - Fork 807
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to redefine dynamically created classes? #1698
Comments
This is not possible with injection as the class loader cannot be patched to resolve the class file. You could use Alternatively, you can use an |
Hello, I used
Testing has found that |
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. 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
Project dependencies
|
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
The text was updated successfully, but these errors were encountered: