• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

raphw / byte-buddy / #801

27 Oct 2025 09:37AM UTC coverage: 84.715% (-0.4%) from 85.118%
#801

push

raphw
Fix imports.

29586 of 34924 relevant lines covered (84.72%)

0.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.89
/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/bind/annotation/Super.java
1
/*
2
 * Copyright 2014 - Present Rafael Winterhalter
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package net.bytebuddy.implementation.bind.annotation;
17

18
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19
import net.bytebuddy.description.annotation.AnnotationDescription;
20
import net.bytebuddy.description.enumeration.EnumerationDescription;
21
import net.bytebuddy.description.method.MethodDescription;
22
import net.bytebuddy.description.method.MethodList;
23
import net.bytebuddy.description.method.ParameterDescription;
24
import net.bytebuddy.description.type.TypeDescription;
25
import net.bytebuddy.dynamic.TargetType;
26
import net.bytebuddy.implementation.Implementation;
27
import net.bytebuddy.implementation.auxiliary.TypeProxy;
28
import net.bytebuddy.implementation.bind.MethodDelegationBinder;
29
import net.bytebuddy.implementation.bytecode.StackManipulation;
30
import net.bytebuddy.implementation.bytecode.assign.Assigner;
31

32
import java.lang.annotation.Documented;
33
import java.lang.annotation.ElementType;
34
import java.lang.annotation.Retention;
35
import java.lang.annotation.RetentionPolicy;
36
import java.lang.annotation.Target;
37
import java.lang.reflect.InvocationTargetException;
38
import java.util.Arrays;
39
import java.util.List;
40

41
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
42
import static net.bytebuddy.matcher.ElementMatchers.isPrivate;
43
import static net.bytebuddy.matcher.ElementMatchers.named;
44
import static net.bytebuddy.matcher.ElementMatchers.not;
45
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
46

47
/**
48
 * Parameters that are annotated with this annotation are assigned an instance of an auxiliary proxy type that allows calling
49
 * any {@code super} methods of the instrumented type where the parameter type must be a super type of the instrumented type.
50
 * The proxy type will be a direct subclass of the parameter's type such as for example a specific interface.
51
 * <p>&nbsp;</p>
52
 * Obviously, the proxy type must be instantiated before it is assigned to the intercepting method's parameter. For this
53
 * purpose, two strategies are available which can be specified by setting the {@link Super#strategy()} parameter which can
54
 * be assigned:
55
 * <ol>
56
 * <li>{@link net.bytebuddy.implementation.bind.annotation.Super.Instantiation#CONSTRUCTOR}:
57
 * A constructor call is made where {@link Super#constructorParameters()} determines the constructor's signature. Any constructor
58
 * parameter is assigned the parameter's default value when the constructor is called. Calling the default constructor is the
59
 * preconfigured strategy.</li>
60
 * <li>{@link net.bytebuddy.implementation.bind.annotation.Super.Instantiation#UNSAFE}:
61
 * The proxy is created by making use of Java's {@link sun.reflect.ReflectionFactory} which is however not a public API which
62
 * is why it should be used with care. No constructor is called when this strategy is used. If this option is set, the
63
 * {@link Super#constructorParameters()} parameter is ignored.</li>
64
 * </ol>
65
 * Note that when for example intercepting a type {@code Foo} that implements some interface {@code Bar}, the proxy type
66
 * will only implement {@code Bar} and therefore extend {@link java.lang.Object} what allows for calling the default
67
 * constructor on the proxy. This implies that an interception by some method {@code qux(@Super Baz baz, @Super Bar bar)}
68
 * would cause the creation of two super call proxies, one extending {@code Baz}, the other extending {@code Bar}, give
69
 * that both types are super types of {@code Foo}.
70
 * <p>&nbsp;</p>
71
 * As an exception, no method calls to {@link Object#finalize()} are delegated by calling this method on the {@code super}-call
72
 * proxy by default. If this is absolutely necessary, this can however be enabled by setting {@link Super#ignoreFinalizer()}
73
 * to {@code false}.
74
 * <p>&nbsp;</p>
75
 * If a method parameter is not a super type of the instrumented type, the method with the parameter that is annotated by
76
 * #{@code Super} is not considered a possible delegation target.
77
 *
78
 * @see net.bytebuddy.implementation.MethodDelegation
79
 * @see net.bytebuddy.implementation.bind.annotation.TargetMethodAnnotationDrivenBinder
80
 */
81
@Documented
82
@Retention(RetentionPolicy.RUNTIME)
83
@Target(ElementType.PARAMETER)
84
public @interface Super {
85

86
    /**
87
     * Determines how the {@code super}call proxy type is instantiated.
88
     *
89
     * @return The instantiation strategy for this proxy.
90
     */
91
    Instantiation strategy() default Instantiation.CONSTRUCTOR;
92

93
    /**
94
     * If {@code true}, the proxy type will not implement {@code super} calls to {@link Object#finalize()} or any overridden methods.
95
     *
96
     * @return {@code false} if finalizer methods should be considered for {@code super}-call proxy type delegation.
97
     */
98
    boolean ignoreFinalizer() default true;
99

100
    /**
101
     * Determines if the generated proxy should be {@link java.io.Serializable}. If the annotated type
102
     * already is serializable, such an explicit specification is not required.
103
     *
104
     * @return {@code true} if the generated proxy should be {@link java.io.Serializable}.
105
     */
106
    boolean serializableProxy() default false;
107

108
    /**
109
     * Defines the parameter types of the constructor to be called for the created {@code super}-call proxy type.
110
     *
111
     * @return The parameter types of the constructor to be called.
112
     */
113
    Class<?>[] constructorParameters() default {};
114

115
    /**
116
     * Specifies a class to resolve a constructor of the proxied type to use for instantiation if
117
     * {@link Instantiation#CONSTRUCTOR} is used. Note that the specified class will be loaded and instantiated by
118
     * Byte Buddy in order to resolve the constructor. For this, the specified class requires a public
119
     * default constructor.
120
     *
121
     * @return The type of the {@link ConstructorResolver} to use.
122
     */
123
    Class<? extends ConstructorResolver> constructorResolver() default ConstructorResolver.Default.class;
124

125
    /**
126
     * Determines the type that is implemented by the proxy. When this value is set to its default value
127
     * {@code void}, the proxy is created as an instance of the parameter's type. When it is set to
128
     * {@link TargetType}, it is created as an instance of the generated class. Otherwise, the proxy type
129
     * is set to the given value.
130
     *
131
     * @return The type of the proxy or an indicator type, i.e. {@code void} or {@link TargetType}.
132
     */
133
    Class<?> proxyType() default void.class;
134

135
    /**
136
     * A constructor resolver is responsible to specify the constructor to be used for creating a proxy.
137
     */
138
    interface ConstructorResolver {
139

140
        /**
141
         * Resolves the constructor to be used.
142
         *
143
         * @param proxiedType           The type being proxied.
144
         * @param constructorParameters The types being specified on the annotation.
145
         * @return The constructor to invoke with default arguments for instantiation.
146
         */
147
        MethodDescription.InDefinedShape resolve(TypeDescription proxiedType, List<TypeDescription> constructorParameters);
148

149
        /**
150
         * A default constructor resolver that attempts to resolve a constructor with the given argument types.
151
         */
152
        class Default implements ConstructorResolver {
1✔
153

154
            /**
155
             * {@inheritDoc}
156
             */
157
            public MethodDescription.InDefinedShape resolve(TypeDescription proxiedType, List<TypeDescription> constructorParameters) {
158
                if (proxiedType.isInterface()) {
1✔
159
                    return TypeDescription.ForLoadedType.of(Object.class).getDeclaredMethods()
1✔
160
                            .filter(isConstructor())
1✔
161
                            .getOnly();
1✔
162
                }
163
                MethodList<MethodDescription.InDefinedShape> candidates = proxiedType.getDeclaredMethods().filter(isConstructor()
1✔
164
                        .and(not(isPrivate()))
1✔
165
                        .and(takesArguments(constructorParameters)));
1✔
166
                if (candidates.size() == 1) {
1✔
167
                    return candidates.getOnly();
1✔
168
                } else {
169
                    throw new IllegalStateException("Did not discover exactly one constructor on " + proxiedType + " with parameters " + constructorParameters);
×
170
                }
171
            }
172
        }
173
    }
174

175
    /**
176
     * Determines the instantiation of the proxy type.
177
     *
178
     * @see net.bytebuddy.implementation.bind.annotation.Super
179
     */
180
    enum Instantiation {
1✔
181

182
        /**
183
         * A proxy instance is instantiated by its constructor. For the constructor's arguments, the parameters default
184
         * values are used. The constructor can be identified by setting {@link Super#constructorParameters()}.
185
         */
186
        CONSTRUCTOR {
1✔
187
            @Override
188
            protected StackManipulation proxyFor(TypeDescription proxyType,
189
                                                 Implementation.Target implementationTarget,
190
                                                 AnnotationDescription.Loadable<Super> annotation) {
191
                MethodDescription.InDefinedShape constructor;
192
                try {
193
                    @SuppressWarnings("unchecked")
194
                    ConstructorResolver constructorResolver = (ConstructorResolver) annotation.getValue(CONSTRUCTOR_RESOLVER)
1✔
195
                            .load(ConstructorResolver.class.getClassLoader())
1✔
196
                            .resolve(Class.class)
1✔
197
                            .getConstructor()
1✔
198
                            .newInstance();
1✔
199
                    constructor = constructorResolver.resolve(
1✔
200
                            proxyType,
201
                            Arrays.asList(annotation.getValue(CONSTRUCTOR_PARAMETERS).resolve(TypeDescription[].class)));
1✔
202
                } catch (NoSuchMethodException exception) {
×
203
                    throw new IllegalStateException("No default constructor specified by " + annotation.getValue(CONSTRUCTOR_RESOLVER)
×
204
                            .resolve(TypeDescription.class)
×
205
                            .getName(), exception);
×
206
                } catch (InvocationTargetException exception) {
×
207
                    throw new IllegalStateException("Failed to resolve constructor specified by " + annotation, exception.getTargetException());
×
208
                } catch (Exception exception) {
×
209
                    throw new IllegalStateException("Failed to resolve constructor specified by " + annotation, exception);
×
210
                }
1✔
211
                return new TypeProxy.ForSuperMethodByConstructor(proxyType,
1✔
212
                        constructor,
213
                        implementationTarget,
214
                        annotation.getValue(IGNORE_FINALIZER).resolve(Boolean.class),
1✔
215
                        annotation.getValue(SERIALIZABLE_PROXY).resolve(Boolean.class));
1✔
216
            }
217
        },
218

219
        /**
220
         * A proxy is instantiated by calling JVM internal methods and without calling a constructor. This strategy
221
         * might fail on exotic JVM implementations.
222
         */
223
        UNSAFE {
1✔
224
            @Override
225
            protected StackManipulation proxyFor(TypeDescription proxyType,
226
                                                 Implementation.Target implementationTarget,
227
                                                 AnnotationDescription.Loadable<Super> annotation) {
228
                return new TypeProxy.ForSuperMethodByReflectionFactory(proxyType,
1✔
229
                        implementationTarget,
230
                        annotation.getValue(IGNORE_FINALIZER).resolve(Boolean.class),
1✔
231
                        annotation.getValue(SERIALIZABLE_PROXY).resolve(Boolean.class));
1✔
232
            }
233
        };
234

235
        /**
236
         * A reference to the ignore finalizer method.
237
         */
238
        private static final MethodDescription.InDefinedShape IGNORE_FINALIZER;
239

240
        /**
241
         * A reference to the serializable proxy method.
242
         */
243
        private static final MethodDescription.InDefinedShape SERIALIZABLE_PROXY;
244

245
        /**
246
         * A reference to the constructor parameters method.
247
         */
248
        private static final MethodDescription.InDefinedShape CONSTRUCTOR_PARAMETERS;
249

250
        /**
251
         * A reference to the constructor parameters resolver method.
252
         */
253
        private static final MethodDescription.InDefinedShape CONSTRUCTOR_RESOLVER;
254

255
        /*
256
         * Extracts method references to the annotation methods.
257
         */
258
        static {
259
            MethodList<MethodDescription.InDefinedShape> annotationProperties = TypeDescription.ForLoadedType.of(Super.class).getDeclaredMethods();
1✔
260
            IGNORE_FINALIZER = annotationProperties.filter(named("ignoreFinalizer")).getOnly();
1✔
261
            SERIALIZABLE_PROXY = annotationProperties.filter(named("serializableProxy")).getOnly();
1✔
262
            CONSTRUCTOR_PARAMETERS = annotationProperties.filter(named("constructorParameters")).getOnly();
1✔
263
            CONSTRUCTOR_RESOLVER = annotationProperties.filter(named("constructorResolver")).getOnly();
1✔
264
        }
1✔
265

266
        /**
267
         * Creates a stack manipulation which loads a {@code super}-call proxy onto the stack.
268
         *
269
         * @param proxyType            The type of the proxy that is bound to the parameter annotated by
270
         *                             {@link net.bytebuddy.implementation.bind.annotation.Super}
271
         * @param implementationTarget The implementation target for the currently created type.
272
         * @param annotation           The annotation that caused this method call.
273
         * @return A stack manipulation representing this instance's instantiation strategy.
274
         */
275
        protected abstract StackManipulation proxyFor(TypeDescription proxyType,
276
                                                      Implementation.Target implementationTarget,
277
                                                      AnnotationDescription.Loadable<Super> annotation);
278
    }
279

280
    /**
281
     * A binder for handling the
282
     * {@link net.bytebuddy.implementation.bind.annotation.Super}
283
     * annotation.
284
     *
285
     * @see TargetMethodAnnotationDrivenBinder
286
     */
287
    enum Binder implements TargetMethodAnnotationDrivenBinder.ParameterBinder<Super> {
1✔
288

289
        /**
290
         * The singleton instance.
291
         */
292
        INSTANCE;
1✔
293

294
        /**
295
         * A method reference to the strategy property.
296
         */
297
        private static final MethodDescription.InDefinedShape STRATEGY;
298

299
        /**
300
         * A reference to the proxy type property.
301
         */
302
        private static final MethodDescription.InDefinedShape PROXY_TYPE;
303

304
        /*
305
         * Extracts method references of the super annotation.
306
         */
307
        static {
308
            MethodList<MethodDescription.InDefinedShape> annotationProperties = TypeDescription.ForLoadedType.of(Super.class).getDeclaredMethods();
1✔
309
            STRATEGY = annotationProperties.filter(named("strategy")).getOnly();
1✔
310
            PROXY_TYPE = annotationProperties.filter(named("proxyType")).getOnly();
1✔
311
        }
1✔
312

313
        /**
314
         * {@inheritDoc}
315
         */
316
        public Class<Super> getHandledType() {
317
            return Super.class;
1✔
318
        }
319

320
        /**
321
         * {@inheritDoc}
322
         */
323
        public MethodDelegationBinder.ParameterBinding<?> bind(AnnotationDescription.Loadable<Super> annotation,
324
                                                               MethodDescription source,
325
                                                               ParameterDescription target,
326
                                                               Implementation.Target implementationTarget,
327
                                                               Assigner assigner,
328
                                                               Assigner.Typing typing) {
329
            if (target.getType().isPrimitive() || target.getType().isArray()) {
1✔
330
                throw new IllegalStateException(target + " uses the @Super annotation on an invalid type");
1✔
331
            }
332
            TypeDescription proxyType = TypeLocator.ForType
1✔
333
                    .of(annotation.getValue(PROXY_TYPE).resolve(TypeDescription.class))
1✔
334
                    .resolve(implementationTarget.getInstrumentedType(), target.getType());
1✔
335
            if (proxyType.isFinal()) {
1✔
336
                throw new IllegalStateException("Cannot extend final type as @Super proxy: " + proxyType);
1✔
337
            } else if (source.isStatic() || !implementationTarget.getInstrumentedType().isAssignableTo(proxyType)) {
1✔
338
                return MethodDelegationBinder.ParameterBinding.Illegal.INSTANCE;
1✔
339
            } else {
340
                return new MethodDelegationBinder.ParameterBinding.Anonymous(annotation
1✔
341
                        .getValue(STRATEGY).resolve(EnumerationDescription.class).load(Instantiation.class)
1✔
342
                        .proxyFor(proxyType, implementationTarget, annotation));
1✔
343
            }
344
        }
345

346
        /**
347
         * Locates the type which should be the base type of the created proxy.
348
         */
349
        protected interface TypeLocator {
350

351
            /**
352
             * Resolves the target type.
353
             *
354
             * @param instrumentedType The instrumented type.
355
             * @param parameterType    The type of the target parameter.
356
             * @return The proxy type.
357
             */
358
            TypeDescription resolve(TypeDescription instrumentedType, TypeDescription.Generic parameterType);
359

360
            /**
361
             * A type locator that yields the instrumented type.
362
             */
363
            enum ForInstrumentedType implements TypeLocator {
1✔
364

365
                /**
366
                 * The singleton instance.
367
                 */
368
                INSTANCE;
1✔
369

370
                /**
371
                 * {@inheritDoc}
372
                 */
373
                public TypeDescription resolve(TypeDescription instrumentedType, TypeDescription.Generic parameterType) {
374
                    return instrumentedType;
1✔
375
                }
376
            }
377

378
            /**
379
             * A type locator that yields the target parameter's type.
380
             */
381
            enum ForParameterType implements TypeLocator {
1✔
382

383
                /**
384
                 * The singleton instance.
385
                 */
386
                INSTANCE;
1✔
387

388
                /**
389
                 * {@inheritDoc}
390
                 */
391
                public TypeDescription resolve(TypeDescription instrumentedType, TypeDescription.Generic parameterType) {
392
                    TypeDescription erasure = parameterType.asErasure();
1✔
393
                    return erasure.equals(instrumentedType)
1✔
394
                            ? instrumentedType
395
                            : erasure;
396
                }
397
            }
398

399
            /**
400
             * A type locator that returns a given type.
401
             */
402
            @HashCodeAndEqualsPlugin.Enhance
403
            class ForType implements TypeLocator {
404

405
                /**
406
                 * The type to be returned upon resolution.
407
                 */
408
                private final TypeDescription typeDescription;
409

410
                /**
411
                 * Creates a new type locator for a given type.
412
                 *
413
                 * @param typeDescription The type to be returned upon resolution.
414
                 */
415
                protected ForType(TypeDescription typeDescription) {
1✔
416
                    this.typeDescription = typeDescription;
1✔
417
                }
1✔
418

419
                /**
420
                 * Resolves a type locator based upon an annotation value.
421
                 *
422
                 * @param typeDescription The annotation's value.
423
                 * @return The appropriate type locator.
424
                 */
425
                protected static TypeLocator of(TypeDescription typeDescription) {
426
                    if (typeDescription.represents(void.class)) {
1✔
427
                        return ForParameterType.INSTANCE;
1✔
428
                    } else if (typeDescription.represents(TargetType.class)) {
1✔
429
                        return ForInstrumentedType.INSTANCE;
1✔
430
                    } else if (typeDescription.isPrimitive() || typeDescription.isArray()) {
1✔
431
                        throw new IllegalStateException("Cannot assign proxy to " + typeDescription);
1✔
432
                    } else {
433
                        return new ForType(typeDescription);
1✔
434
                    }
435
                }
436

437
                /**
438
                 * {@inheritDoc}
439
                 */
440
                public TypeDescription resolve(TypeDescription instrumentedType, TypeDescription.Generic parameterType) {
441
                    if (!typeDescription.isAssignableTo(parameterType.asErasure())) {
1✔
442
                        throw new IllegalStateException("Impossible to assign " + typeDescription + " to parameter of type " + parameterType);
1✔
443
                    }
444
                    return typeDescription;
1✔
445
                }
446
            }
447
        }
448
    }
449
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc