I have a class with default visibility without any explicit constructors. i want to generate similar class (with same methods and annotations) but with explicit public default constructor. is it possible in easy way? any ready to use proxy frameworks? i'm afraid that doing it manually with cglib will be rather big task
Asked
Active
Viewed 398 times
0
-
i need it dynamically. i got a class as an input – piotrek Jan 09 '15 at 23:24
-
then cglib. It's not a big task. Just ugly. – Dima Jan 10 '15 at 00:00
-
The compiler will generate a constructor for you anyway. At the bytecode level, there is no difference. – Antimony Jan 10 '15 at 01:56
-
true but implicit constructor of non-public class is not visible in `Class.getConstructors()`. i need to create a class with parameterless constructor returned from this method – piotrek Jan 10 '15 at 11:31
1 Answers
1
cglib will always override methods without copying annotations. There is no support for annotations in cglib as it was written before Java 5 came out.
If you are open to using a different library than cglib, have a look at my library Byte Buddy for defining such constructors. Using it, you can either define a Java agent for increasing the original class's visibility or you can create a subclass where you instruct retaining libraries.
A subclass would be generated somewhat as follows:
DynamicType.Builder<? extends Foo> builder = new ByteBuddy()
.subclass(Foo.class, ConstructorStrategy.Default.NO_CONSTRUCTORS)
.modifiers(() -> return Foo.class.getModifiers() | Modifiers.PUBLIC);
Foo.class.getDeclaredConstructors().forEach( c ->
DynamicType.Builder.MethodAnnotationTarget<? extends Foo> target = builder
.defineConstructor(Arrays.asList(c.getParamaterTypes),
() -> return c.getModifiers() | Modifiers.PUBLIC)
.intercept(SuperMethodCall.INSTANCE)
.annotateMethod(c.getAnnotations());
int index = 0;
for(Annotation[] a : c.getParameterAnnotatations()) {
target = target.annotateParameter(index++, a);
}
builder = target;
)
Class<? extends Foo> subclass = builder.make()
.load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
This looks like a lot of code at first (I am currently enhancing the API to make this much shorter. What you however do is the following:
- You define a new subclass of
Foo
and instruct Byte Buddy not to add any constructors. - You define the modifiers of this class to resemble those of
Foo
but additionally bepublic
. - You look up all constructors that
Foo
declares and for each such constructor, you define a new constructor for the generated subclass. This constructor defines the exact same parameter types as the constructor ofFoo
and also copies the modifiers. Additionally, the visibility is however set to becomepublic
. - You copy all annotations of
Foo
's constructor to become present on the subclass's constructor. - You repeat this for all parameter annotations.
- You make and load the class (on
Foo
's class loader).

Rafael Winterhalter
- 42,759
- 13
- 108
- 192