0

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

4
  • i need it dynamically. i got a class as an input Commented Jan 9, 2015 at 23:24
  • then cglib. It's not a big task. Just ugly. Commented Jan 10, 2015 at 0:00
  • The compiler will generate a constructor for you anyway. At the bytecode level, there is no difference. Commented Jan 10, 2015 at 1: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 Commented Jan 10, 2015 at 11:31

1 Answer 1

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:

  1. You define a new subclass of Foo and instruct Byte Buddy not to add any constructors.
  2. You define the modifiers of this class to resemble those of Foo but additionally be public.
  3. 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 of Foo and also copies the modifiers. Additionally, the visibility is however set to become public.
  4. You copy all annotations of Foo's constructor to become present on the subclass's constructor.
  5. You repeat this for all parameter annotations.
  6. You make and load the class (on Foo's class loader).
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.