• 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

90.7
/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/subclass/ConstructorStrategy.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.dynamic.scaffold.subclass;
17

18
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19
import net.bytebuddy.description.method.MethodDescription;
20
import net.bytebuddy.description.method.MethodList;
21
import net.bytebuddy.description.type.TypeDescription;
22
import net.bytebuddy.dynamic.Transformer;
23
import net.bytebuddy.dynamic.scaffold.MethodRegistry;
24
import net.bytebuddy.implementation.MethodCall;
25
import net.bytebuddy.implementation.SuperMethodCall;
26
import net.bytebuddy.implementation.attribute.MethodAttributeAppender;
27
import net.bytebuddy.matcher.ElementMatcher;
28
import net.bytebuddy.matcher.LatentMatcher;
29
import org.objectweb.asm.Opcodes;
30

31
import java.util.ArrayList;
32
import java.util.Collections;
33
import java.util.List;
34

35
import static net.bytebuddy.matcher.ElementMatchers.any;
36
import static net.bytebuddy.matcher.ElementMatchers.is;
37
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
38
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
39
import static net.bytebuddy.matcher.ElementMatchers.isVisibleTo;
40
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
41

42
/**
43
 * A constructor strategy is responsible for creating bootstrap constructors for a
44
 * {@link SubclassDynamicTypeBuilder}.
45
 *
46
 * @see net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy.Default
47
 */
48
public interface ConstructorStrategy {
49

50
    /**
51
     * Extracts constructors for a given super type. The extracted constructor signatures will then be imitated by the
52
     * created dynamic type.
53
     *
54
     * @param instrumentedType The type for which the constructors should be created.
55
     * @return A list of tokens that describe the constructors that are to be implemented.
56
     */
57
    List<MethodDescription.Token> extractConstructors(TypeDescription instrumentedType);
58

59
    /**
60
     * Returns a method registry that is capable of creating byte code for the constructors that were
61
     * provided by the
62
     * {@link net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy#extractConstructors(TypeDescription)}
63
     * method of this instance.
64
     *
65
     * @param instrumentedType The instrumented type.
66
     * @param methodRegistry   The original method registry.
67
     * @return A method registry that is capable of providing byte code for the constructors that were added by this strategy.
68
     */
69
    MethodRegistry inject(TypeDescription instrumentedType, MethodRegistry methodRegistry);
70

71
    /**
72
     * Default implementations of constructor strategies. Any such strategy offers to additionally apply an {@link MethodAttributeAppender.Factory}.
73
     */
74
    enum Default implements ConstructorStrategy {
1✔
75

76
        /**
77
         * This strategy is adding no constructors such that the instrumented type will by default not have any. This
78
         * is legal by Java byte code requirements. However, if no constructor is added manually if this strategy is
79
         * applied, the type is not constructable without using JVM non-public functionality.
80
         */
81
        NO_CONSTRUCTORS {
1✔
82
            @Override
83
            protected List<MethodDescription.Token> doExtractConstructors(TypeDescription superClass) {
84
                return Collections.emptyList();
1✔
85
            }
86

87
            @Override
88
            protected MethodRegistry doInject(MethodRegistry methodRegistry, MethodAttributeAppender.Factory methodAttributeAppenderFactory) {
89
                return methodRegistry;
1✔
90
            }
91
        },
92

93
        /**
94
         * This strategy is adding a default constructor that calls its super types default constructor. If no such
95
         * constructor is defined by the super class, an {@link IllegalArgumentException} is thrown. Note that the default
96
         * constructor needs to be visible to its sub type for this strategy to work. The declared default constructor of
97
         * the created class is declared public and without annotations.
98
         */
99
        DEFAULT_CONSTRUCTOR {
1✔
100
            @Override
101
            protected List<MethodDescription.Token> doExtractConstructors(TypeDescription instrumentedType) {
102
                TypeDescription.Generic superClass = instrumentedType.getSuperClass();
1✔
103
                MethodList<?> defaultConstructors = superClass == null
1✔
104
                        ? new MethodList.Empty<MethodDescription.InGenericShape>()
105
                        : superClass.getDeclaredMethods().filter(isConstructor().and(takesArguments(0)).<MethodDescription>and(isVisibleTo(instrumentedType)));
1✔
106
                if (defaultConstructors.size() == 1) {
1✔
107
                    return Collections.singletonList(new MethodDescription.Token(Opcodes.ACC_PUBLIC));
1✔
108
                } else {
109
                    throw new IllegalArgumentException(instrumentedType.getSuperClass() + " declares no constructor that is visible to " + instrumentedType);
1✔
110
                }
111
            }
112

113
            @Override
114
            protected MethodRegistry doInject(MethodRegistry methodRegistry, MethodAttributeAppender.Factory methodAttributeAppenderFactory) {
115
                return methodRegistry.append(new LatentMatcher.Resolved<MethodDescription>(isConstructor()),
1✔
116
                        new MethodRegistry.Handler.ForImplementation(SuperMethodCall.INSTANCE),
117
                        methodAttributeAppenderFactory,
118
                        Transformer.NoOp.<MethodDescription>make());
1✔
119
            }
120
        },
121

122
        /**
123
         * This strategy is adding all constructors of the instrumented type's super class where each constructor is
124
         * directly invoking its signature-equivalent super class constructor. Only constructors that are visible to the
125
         * instrumented type are added, i.e. package-private constructors are only added if the super type is defined
126
         * in the same package as the instrumented type and private constructors are always skipped.
127
         */
128
        IMITATE_SUPER_CLASS {
1✔
129
            @Override
130
            protected List<MethodDescription.Token> doExtractConstructors(TypeDescription instrumentedType) {
131
                TypeDescription.Generic superClass = instrumentedType.getSuperClass();
1✔
132
                return (superClass == null
1✔
133
                        ? new MethodList.Empty<MethodDescription.InGenericShape>()
134
                        : superClass.getDeclaredMethods().filter(isConstructor().and(isVisibleTo(instrumentedType)))).asTokenList(is(instrumentedType));
1✔
135
            }
136

137
            @Override
138
            public MethodRegistry doInject(MethodRegistry methodRegistry, MethodAttributeAppender.Factory methodAttributeAppenderFactory) {
139
                return methodRegistry.append(new LatentMatcher.Resolved<MethodDescription>(isConstructor()),
1✔
140
                        new MethodRegistry.Handler.ForImplementation(SuperMethodCall.INSTANCE),
141
                        methodAttributeAppenderFactory,
142
                        Transformer.NoOp.<MethodDescription>make());
1✔
143
            }
144
        },
145

146
        /**
147
         * This strategy is adding all constructors of the instrumented type's super class where each constructor is
148
         * directly invoking its signature-equivalent super class constructor. Only {@code public} constructors are
149
         * added.
150
         */
151
        IMITATE_SUPER_CLASS_PUBLIC {
1✔
152
            @Override
153
            protected List<MethodDescription.Token> doExtractConstructors(TypeDescription instrumentedType) {
154
                TypeDescription.Generic superClass = instrumentedType.getSuperClass();
1✔
155
                return (superClass == null
1✔
156
                        ? new MethodList.Empty<MethodDescription.InGenericShape>()
157
                        : superClass.getDeclaredMethods().filter(isPublic().and(isConstructor()))).asTokenList(is(instrumentedType));
1✔
158
            }
159

160
            @Override
161
            public MethodRegistry doInject(MethodRegistry methodRegistry, MethodAttributeAppender.Factory methodAttributeAppenderFactory) {
162
                return methodRegistry.append(new LatentMatcher.Resolved<MethodDescription>(isConstructor()),
1✔
163
                        new MethodRegistry.Handler.ForImplementation(SuperMethodCall.INSTANCE),
164
                        methodAttributeAppenderFactory,
165
                        Transformer.NoOp.<MethodDescription>make());
1✔
166
            }
167
        },
168

169
        /**
170
         * This strategy is adding all constructors of the instrumented type's super class where each constructor is
171
         * directly invoking its signature-equivalent super class constructor. A constructor is added for any constructor
172
         * of the super class that is invokable and is declared as {@code public}.
173
         */
174
        IMITATE_SUPER_CLASS_OPENING {
1✔
175
            @Override
176
            protected List<MethodDescription.Token> doExtractConstructors(TypeDescription instrumentedType) {
177
                TypeDescription.Generic superClass = instrumentedType.getSuperClass();
1✔
178
                return (superClass == null
1✔
179
                        ? new MethodList.Empty<MethodDescription.InGenericShape>()
180
                        : superClass.getDeclaredMethods().filter(isConstructor().and(isVisibleTo(instrumentedType)))).asTokenList(is(instrumentedType));
1✔
181
            }
182

183
            @Override
184
            public MethodRegistry doInject(MethodRegistry methodRegistry, MethodAttributeAppender.Factory methodAttributeAppenderFactory) {
185
                return methodRegistry.append(new LatentMatcher.Resolved<MethodDescription>(isConstructor()),
1✔
186
                        new MethodRegistry.Handler.ForImplementation(SuperMethodCall.INSTANCE),
187
                        methodAttributeAppenderFactory,
188
                        Transformer.NoOp.<MethodDescription>make());
1✔
189
            }
190

191
            @Override
192
            protected int resolveModifier(int modifiers) {
193
                return Opcodes.ACC_PUBLIC;
1✔
194
            }
195
        };
196

197
        /**
198
         * {@inheritDoc}
199
         */
200
        public List<MethodDescription.Token> extractConstructors(TypeDescription instrumentedType) {
201
            List<MethodDescription.Token> tokens = doExtractConstructors(instrumentedType), stripped = new ArrayList<MethodDescription.Token>(tokens.size());
1✔
202
            for (MethodDescription.Token token : tokens) {
1✔
203
                stripped.add(new MethodDescription.Token(token.getName(),
1✔
204
                        resolveModifier(token.getModifiers()),
1✔
205
                        token.getTypeVariableTokens(),
1✔
206
                        token.getReturnType(),
1✔
207
                        token.getParameterTokens(),
1✔
208
                        token.getExceptionTypes(),
1✔
209
                        token.getAnnotations(),
1✔
210
                        token.getDefaultValue(),
1✔
211
                        TypeDescription.Generic.UNDEFINED));
212
            }
1✔
213
            return stripped;
1✔
214
        }
215

216
        /**
217
         * Resolves a constructor's modifiers.
218
         *
219
         * @param modifiers The actual constructor's modifiers.
220
         * @return The resolved modifiers.
221
         */
222
        protected int resolveModifier(int modifiers) {
223
            return modifiers;
1✔
224
        }
225

226
        /**
227
         * Extracts the relevant method tokens of the instrumented type's constructors.
228
         *
229
         * @param instrumentedType The type for which to extract the constructors.
230
         * @return A list of relevant method tokens.
231
         */
232
        protected abstract List<MethodDescription.Token> doExtractConstructors(TypeDescription instrumentedType);
233

234
        /**
235
         * {@inheritDoc}
236
         */
237
        public MethodRegistry inject(TypeDescription instrumentedType, MethodRegistry methodRegistry) {
238
            return doInject(methodRegistry, MethodAttributeAppender.NoOp.INSTANCE);
1✔
239
        }
240

241
        /**
242
         * Applies the actual injection with a method attribute appender factory supplied.
243
         *
244
         * @param methodRegistry                 The method registry into which to inject the constructors.
245
         * @param methodAttributeAppenderFactory The method attribute appender to use.
246
         * @return The resulting method registry.
247
         */
248
        protected abstract MethodRegistry doInject(MethodRegistry methodRegistry, MethodAttributeAppender.Factory methodAttributeAppenderFactory);
249

250
        /**
251
         * Returns a constructor strategy that supplies the supplied method attribute appender factory.
252
         *
253
         * @param methodAttributeAppenderFactory The method attribute appender factory to use.
254
         * @return A copy of this constructor strategy with the method attribute appender factory applied.
255
         */
256
        public ConstructorStrategy with(MethodAttributeAppender.Factory methodAttributeAppenderFactory) {
257
            return new WithMethodAttributeAppenderFactory(this, methodAttributeAppenderFactory);
1✔
258
        }
259

260
        /**
261
         * Applies this constructor strategy while retaining any of the base constructor's annotations.
262
         *
263
         * @return A copy of this constructor strategy which retains any of the base constructor's annotations.
264
         */
265
        public ConstructorStrategy withInheritedAnnotations() {
266
            return new WithMethodAttributeAppenderFactory(this, MethodAttributeAppender.ForInstrumentedMethod.EXCLUDING_RECEIVER);
1✔
267
        }
268

269
        /**
270
         * A wrapper for a default constructor strategy which additionally applies a method attribute appender factory.
271
         */
272
        @HashCodeAndEqualsPlugin.Enhance
273
        protected static class WithMethodAttributeAppenderFactory implements ConstructorStrategy {
274

275
            /**
276
             * The delegate default constructor strategy.
277
             */
278
            private final Default delegate;
279

280
            /**
281
             * The method attribute appender factory to apply.
282
             */
283
            private final MethodAttributeAppender.Factory methodAttributeAppenderFactory;
284

285
            /**
286
             * Creates a new wrapper for a default constructor strategy.
287
             *
288
             * @param delegate                       The delegate default constructor strategy.
289
             * @param methodAttributeAppenderFactory The method attribute appender factory to apply.
290
             */
291
            protected WithMethodAttributeAppenderFactory(Default delegate, MethodAttributeAppender.Factory methodAttributeAppenderFactory) {
1✔
292
                this.delegate = delegate;
1✔
293
                this.methodAttributeAppenderFactory = methodAttributeAppenderFactory;
1✔
294
            }
1✔
295

296
            /**
297
             * {@inheritDoc}
298
             */
299
            public List<MethodDescription.Token> extractConstructors(TypeDescription instrumentedType) {
300
                return delegate.extractConstructors(instrumentedType);
1✔
301
            }
302

303
            /**
304
             * {@inheritDoc}
305
             */
306
            public MethodRegistry inject(TypeDescription instrumentedType, MethodRegistry methodRegistry) {
307
                return delegate.doInject(methodRegistry, methodAttributeAppenderFactory);
1✔
308
            }
309
        }
310
    }
311

312
    /**
313
     * A constructor strategy that creates a default constructor that invokes a super constructor with default arguments.
314
     */
315
    @HashCodeAndEqualsPlugin.Enhance
316
    class ForDefaultConstructor implements ConstructorStrategy {
317

318
        /**
319
         * A matcher to select a super constructor among possible candidates.
320
         */
321
        private final ElementMatcher<? super MethodDescription> elementMatcher;
322

323
        /**
324
         * The method attribute appender factory to apply.
325
         */
326
        private final MethodAttributeAppender.Factory methodAttributeAppenderFactory;
327

328
        /**
329
         * Creates a constructor strategy for invoking a super constructor with default arguments.
330
         */
331
        public ForDefaultConstructor() {
332
            this(any());
1✔
333
        }
1✔
334

335
        /**
336
         * Creates a constructor strategy for invoking a super constructor with default arguments.
337
         *
338
         * @param elementMatcher A matcher to select a super constructor among possible candidates.
339
         */
340
        public ForDefaultConstructor(ElementMatcher<? super MethodDescription> elementMatcher) {
341
            this(elementMatcher, MethodAttributeAppender.NoOp.INSTANCE);
1✔
342
        }
1✔
343

344
        /**
345
         * Creates a constructor strategy for invoking a super constructor with default arguments.
346
         *
347
         * @param methodAttributeAppenderFactory The method attribute appender factory to apply.
348
         */
349
        public ForDefaultConstructor(MethodAttributeAppender.Factory methodAttributeAppenderFactory) {
350
            this(any(), methodAttributeAppenderFactory);
×
351
        }
×
352

353
        /**
354
         * Creates a constructor strategy for invoking a super constructor with default arguments.
355
         *
356
         * @param elementMatcher                 A matcher to select a super constructor among possible candidates.
357
         * @param methodAttributeAppenderFactory The method attribute appender factory to apply.
358
         */
359
        public ForDefaultConstructor(ElementMatcher<? super MethodDescription> elementMatcher,
360
                                     MethodAttributeAppender.Factory methodAttributeAppenderFactory) {
1✔
361
            this.elementMatcher = elementMatcher;
1✔
362
            this.methodAttributeAppenderFactory = methodAttributeAppenderFactory;
1✔
363
        }
1✔
364

365
        /**
366
         * {@inheritDoc}
367
         */
368
        public List<MethodDescription.Token> extractConstructors(TypeDescription instrumentedType) {
369
            TypeDescription.Generic superClass = instrumentedType.getSuperClass();
1✔
370
            if (superClass == null) {
1✔
371
                throw new IllegalArgumentException("Cannot extract constructors for " + instrumentedType);
×
372
            } else if (superClass.getDeclaredMethods().filter(isConstructor()).isEmpty()) {
1✔
373
                throw new IllegalStateException("Cannot define default constructor for class without super class constructor");
1✔
374
            }
375
            return Collections.singletonList(new MethodDescription.Token(Opcodes.ACC_PUBLIC));
1✔
376
        }
377

378
        /**
379
         * {@inheritDoc}
380
         */
381
        public MethodRegistry inject(TypeDescription instrumentedType, MethodRegistry methodRegistry) {
382
            TypeDescription.Generic superClass = instrumentedType.getSuperClass();
1✔
383
            if (superClass == null) {
1✔
384
                throw new IllegalArgumentException("Cannot inject constructors for " + instrumentedType);
×
385
            }
386
            MethodList<?> candidates = superClass.getDeclaredMethods().filter(isConstructor().and(elementMatcher));
1✔
387
            if (candidates.isEmpty()) {
1✔
388
                throw new IllegalStateException("No possible candidate for super constructor invocation in " + superClass);
1✔
389
            } else if (!candidates.filter(takesArguments(0)).isEmpty()) {
1✔
390
                candidates = candidates.filter(takesArguments(0));
1✔
391
            } else if (candidates.size() > 1) {
×
392
                throw new IllegalStateException("More than one possible super constructor for constructor delegation: " + candidates);
×
393
            }
394
            MethodCall methodCall = MethodCall.invoke(candidates.getOnly());
1✔
395
            for (TypeDescription typeDescription : candidates.getOnly().getParameters().asTypeList().asErasures()) {
1✔
396
                methodCall = methodCall.with(typeDescription.getDefaultValue());
×
397
            }
×
398
            return methodRegistry.append(new LatentMatcher.Resolved<MethodDescription>(isConstructor().and(takesArguments(0))),
1✔
399
                    new MethodRegistry.Handler.ForImplementation(methodCall),
400
                    methodAttributeAppenderFactory,
401
                    Transformer.NoOp.<MethodDescription>make());
1✔
402
        }
403
    }
404
}
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