• 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

92.52
/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/FixedValue.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;
17

18
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19
import net.bytebuddy.description.field.FieldDescription;
20
import net.bytebuddy.description.method.MethodDescription;
21
import net.bytebuddy.description.method.ParameterDescription;
22
import net.bytebuddy.description.type.TypeDescription;
23
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
24
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
25
import net.bytebuddy.implementation.bytecode.StackManipulation;
26
import net.bytebuddy.implementation.bytecode.assign.Assigner;
27
import net.bytebuddy.implementation.bytecode.constant.ClassConstant;
28
import net.bytebuddy.implementation.bytecode.constant.NullConstant;
29
import net.bytebuddy.implementation.bytecode.member.FieldAccess;
30
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
31
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
32
import net.bytebuddy.utility.ConstantValue;
33
import net.bytebuddy.utility.JavaConstant;
34
import net.bytebuddy.utility.RandomString;
35
import org.objectweb.asm.MethodVisitor;
36
import org.objectweb.asm.Opcodes;
37

38
import static net.bytebuddy.matcher.ElementMatchers.named;
39

40
/**
41
 * This implementation returns a fixed value for a method. Other than the {@link net.bytebuddy.implementation.StubMethod}
42
 * implementation, this implementation allows to determine a specific value which must be assignable to the returning value
43
 * of any instrumented method. Otherwise, an exception will be thrown.
44
 *
45
 * @see FieldAccessor
46
 */
47
@HashCodeAndEqualsPlugin.Enhance
48
public abstract class FixedValue implements Implementation {
49

50
    /**
51
     * The assigner that is used for assigning the fixed value to a method's return type.
52
     */
53
    protected final Assigner assigner;
54

55
    /**
56
     * Indicates if dynamic type castings should be attempted for incompatible assignments.
57
     */
58
    protected final Assigner.Typing typing;
59

60
    /**
61
     * Creates a new fixed value implementation.
62
     *
63
     * @param assigner The assigner to use for assigning the fixed value to the return type of the instrumented value.
64
     * @param typing   Indicates if dynamic type castings should be attempted for incompatible assignments.
65
     */
66
    protected FixedValue(Assigner assigner, Assigner.Typing typing) {
1✔
67
        this.assigner = assigner;
1✔
68
        this.typing = typing;
1✔
69
    }
1✔
70

71
    /**
72
     * <p>
73
     * Returns a fixed value from any intercepted method. The fixed value is stored in the constant pool if this is possible.
74
     * Specifically, an argument that is a {@link JavaConstant}, {@link TypeDescription}, primitive, {@link String} or
75
     * {@link Class} value is stored in the constant pool.  Since Java 7, {@code MethodHandle} as well as {@code MethodType}
76
     * references are also supported. Alternatively, the fixed value is stored in a static field.
77
     * </p>
78
     * <p>
79
     * When a value is stored in the class's constant pool, its identity is lost. If an object's identity is important, the
80
     * {@link FixedValue#reference(Object)} method should be used instead.
81
     * </p>
82
     * <p>
83
     * <b>Important</b>: When supplying a method handle or a method type, all types that are implied must be visible to the instrumented
84
     * type or an {@link IllegalAccessException} will be thrown at runtime.
85
     * </p>
86
     *
87
     * @param value The fixed value to return from the method.
88
     * @return An implementation for the given {@code value}.
89
     * @see #value(JavaConstant)
90
     * @see #value(TypeDescription)
91
     * @see #nullValue()
92
     */
93
    public static AssignerConfigurable value(Object value) {
94
        ConstantValue constant = ConstantValue.Simple.wrapOrNull(value);
1✔
95
        return constant == null
1✔
96
                ? reference(value)
1✔
97
                : new ForConstantValue(constant.toStackManipulation(), constant.getTypeDescription());
1✔
98
    }
99

100
    /**
101
     * Other than {@link net.bytebuddy.implementation.FixedValue#value(Object)}, this function
102
     * will create a fixed value implementation that will always defined a field in the instrumented class. As a result,
103
     * object identity will be preserved between the given {@code value} and the value that is returned by
104
     * instrumented methods. The field name can be explicitly determined. The field name is generated from the fixed value's
105
     * hash code.
106
     *
107
     * @param value The fixed value to be returned by methods that are instrumented by this implementation.
108
     * @return An implementation for the given {@code value}.
109
     */
110
    public static AssignerConfigurable reference(Object value) {
111
        return reference(value, ForValue.PREFIX + "$" + RandomString.hashOf(value));
1✔
112
    }
113

114
    /**
115
     * Other than {@link net.bytebuddy.implementation.FixedValue#value(Object)}, this function
116
     * will create a fixed value implementation that will always defined a field in the instrumented class. As a result,
117
     * object identity will be preserved between the given {@code value} and the value that is returned by
118
     * instrumented methods. The field name can be explicitly determined.
119
     *
120
     * @param value The fixed value to be returned by methods that are instrumented by this implementation.
121
     * @param name  The name of the field for storing the fixed value.
122
     * @return An implementation for the given {@code value}.
123
     */
124
    public static AssignerConfigurable reference(Object value, String name) {
125
        return new ForValue(value, name);
1✔
126
    }
127

128
    /**
129
     * Returns the given type in form of a loaded type. The value is loaded from the written class's constant pool.
130
     *
131
     * @param type The type to return from the method.
132
     * @return An implementation for the given {@code value}.
133
     */
134
    public static AssignerConfigurable value(TypeDescription type) {
135
        return new ForConstantValue(ClassConstant.of(type), TypeDescription.ForLoadedType.of(Class.class));
1✔
136
    }
137

138
    /**
139
     * Returns the loaded version of the given {@link JavaConstant}. The value is loaded from the written class's constant pool.
140
     *
141
     * @param constant The type to return from the method.
142
     * @return An implementation for the given {@code value}.
143
     */
144
    public static AssignerConfigurable value(ConstantValue constant) {
145
        return new ForConstantValue(constant.toStackManipulation(), constant.getTypeDescription());
1✔
146
    }
147

148
    /**
149
     * Returns the loaded version of the given {@link JavaConstant}. The value is loaded from the written class's constant pool.
150
     *
151
     * @param constant The type to return from the method.
152
     * @return An implementation for the given {@code value}.
153
     */
154
    public static AssignerConfigurable value(JavaConstant constant) {
155
        return value((ConstantValue) constant);
1✔
156
    }
157

158
    /**
159
     * Returns the argument at the specified index.
160
     *
161
     * @param index The index of the argument to return.
162
     * @return An implementation of a method that returns the argument at the specified index.
163
     */
164
    public static AssignerConfigurable argument(int index) {
165
        if (index < 0) {
1✔
166
            throw new IllegalArgumentException("Argument index cannot be negative: " + index);
1✔
167
        }
168
        return new ForArgument(index);
1✔
169
    }
170

171
    /**
172
     * Returns {@code this} from an instrumented method.
173
     *
174
     * @return An implementation that returns {@code this} from a method.
175
     */
176
    public static AssignerConfigurable self() {
177
        return new ForThisValue();
1✔
178
    }
179

180
    /**
181
     * Returns a {@code null} value from an instrumented method.
182
     *
183
     * @return An implementation that returns {@code null} from a method.
184
     */
185
    public static Implementation nullValue() {
186
        return ForNullValue.INSTANCE;
1✔
187
    }
188

189
    /**
190
     * Returns the origin type from an instrumented method.
191
     *
192
     * @return An implementation that returns the origin type of the current instrumented type.
193
     */
194
    public static AssignerConfigurable originType() {
195
        return new ForOriginType();
1✔
196
    }
197

198
    /**
199
     * Blueprint method that for applying the actual implementation.
200
     *
201
     * @param methodVisitor         The method visitor to which the implementation is applied to.
202
     * @param implementationContext The implementation context for the given implementation.
203
     * @param instrumentedMethod    The instrumented method that is target of the implementation.
204
     * @param typeDescription       A description of the type of the fixed value that is loaded by the
205
     *                              {@code valueLoadingInstruction}.
206
     * @param stackManipulation     A stack manipulation that represents the loading of the fixed value onto the
207
     *                              operand stack.
208
     * @return A representation of the stack and variable array sized that are required for this implementation.
209
     */
210
    protected ByteCodeAppender.Size apply(MethodVisitor methodVisitor,
211
                                          Context implementationContext,
212
                                          MethodDescription instrumentedMethod,
213
                                          TypeDescription.Generic typeDescription,
214
                                          StackManipulation stackManipulation) {
215
        StackManipulation assignment = assigner.assign(typeDescription, instrumentedMethod.getReturnType(), typing);
1✔
216
        if (!assignment.isValid()) {
1✔
217
            throw new IllegalArgumentException("Cannot return value of type " + typeDescription + " for " + instrumentedMethod);
1✔
218
        }
219
        StackManipulation.Size stackSize = new StackManipulation.Compound(
1✔
220
                stackManipulation,
221
                assignment,
222
                MethodReturn.of(instrumentedMethod.getReturnType())
1✔
223
        ).apply(methodVisitor, implementationContext);
1✔
224
        return new ByteCodeAppender.Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize());
1✔
225
    }
226

227
    /**
228
     * Represents a fixed value implementation that is using a default assigner for attempting to assign
229
     * the fixed value to the return type of the instrumented method.
230
     */
231
    public interface AssignerConfigurable extends Implementation {
232

233
        /**
234
         * Defines an explicit assigner to this fixed value implementation.
235
         *
236
         * @param assigner The assigner to use for assigning the fixed value to the return type of the
237
         *                 instrumented value.
238
         * @param typing   Indicates if dynamic type castings should be attempted for incompatible assignments.
239
         * @return A fixed value implementation that makes use of the given assigner.
240
         */
241
        Implementation withAssigner(Assigner assigner, Assigner.Typing typing);
242
    }
243

244
    /**
245
     * A fixed value of {@code null}.
246
     */
247
    protected enum ForNullValue implements Implementation, ByteCodeAppender {
1✔
248

249
        /**
250
         * The singleton instance.
251
         */
252
        INSTANCE;
1✔
253

254
        /**
255
         * {@inheritDoc}
256
         */
257
        public ByteCodeAppender appender(Target implementationTarget) {
258
            return this;
1✔
259
        }
260

261
        /**
262
         * {@inheritDoc}
263
         */
264
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
265
            return instrumentedType;
1✔
266
        }
267

268
        /**
269
         * {@inheritDoc}
270
         */
271
        public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
272
            if (instrumentedMethod.getReturnType().isPrimitive()) {
1✔
273
                throw new IllegalStateException("Cannot return null from " + instrumentedMethod);
1✔
274
            }
275
            return new ByteCodeAppender.Simple(
1✔
276
                    NullConstant.INSTANCE,
277
                    MethodReturn.REFERENCE
278
            ).apply(methodVisitor, implementationContext, instrumentedMethod);
1✔
279
        }
280
    }
281

282
    /**
283
     * A fixed value that appends the origin type of the instrumented type.
284
     */
285
    protected static class ForOriginType extends FixedValue implements AssignerConfigurable {
286

287
        /**
288
         * Creates a new fixed value appender for the origin type.
289
         */
290
        protected ForOriginType() {
291
            this(Assigner.DEFAULT, Assigner.Typing.STATIC);
1✔
292
        }
1✔
293

294
        /**
295
         * Creates a new fixed value appender for the origin type.
296
         *
297
         * @param assigner The assigner to use for assigning the fixed value to the return type of the instrumented value.
298
         * @param typing   Indicates if dynamic type castings should be attempted for incompatible assignments.
299
         */
300
        private ForOriginType(Assigner assigner, Assigner.Typing typing) {
301
            super(assigner, typing);
1✔
302
        }
1✔
303

304
        /**
305
         * {@inheritDoc}
306
         */
307
        public Implementation withAssigner(Assigner assigner, Assigner.Typing typing) {
308
            return new ForOriginType(assigner, typing);
×
309
        }
310

311
        /**
312
         * {@inheritDoc}
313
         */
314
        public ByteCodeAppender appender(Target implementationTarget) {
315
            return new Appender(implementationTarget.getOriginType().asErasure());
1✔
316
        }
317

318
        /**
319
         * {@inheritDoc}
320
         */
321
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
322
            return instrumentedType;
1✔
323
        }
324

325
        /**
326
         * An appender for writing the origin type.
327
         */
328
        @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
329
        protected class Appender implements ByteCodeAppender {
330

331
            /**
332
             * The instrumented type.
333
             */
334
            private final TypeDescription originType;
335

336
            /**
337
             * Creates a new appender.
338
             *
339
             * @param originType The instrumented type.
340
             */
341
            protected Appender(TypeDescription originType) {
1✔
342
                this.originType = originType;
1✔
343
            }
1✔
344

345
            /**
346
             * {@inheritDoc}
347
             */
348
            public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
349
                return ForOriginType.this.apply(methodVisitor,
1✔
350
                        implementationContext,
351
                        instrumentedMethod,
352
                        TypeDescription.ForLoadedType.of(Class.class).asGenericType(),
1✔
353
                        ClassConstant.of(originType));
1✔
354
            }
355
        }
356
    }
357

358
    /**
359
     * A fixed value of {@code this}.
360
     */
361
    protected static class ForThisValue extends FixedValue implements AssignerConfigurable {
362

363
        /**
364
         * Creates an implementation that returns the instance of the instrumented type.
365
         */
366
        protected ForThisValue() {
367
            super(Assigner.DEFAULT, Assigner.Typing.STATIC);
1✔
368
        }
1✔
369

370
        /**
371
         * Creates an implementation that returns the instance of the instrumented type.
372
         *
373
         * @param assigner The assigner to use for assigning the fixed value to the return type of the instrumented value.
374
         * @param typing   Indicates if dynamic type castings should be attempted for incompatible assignments.
375
         */
376
        private ForThisValue(Assigner assigner, Assigner.Typing typing) {
377
            super(assigner, typing);
×
378
        }
×
379

380
        /**
381
         * {@inheritDoc}
382
         */
383
        public ByteCodeAppender appender(Target implementationTarget) {
384
            return new Appender(implementationTarget.getInstrumentedType());
1✔
385
        }
386

387
        /**
388
         * {@inheritDoc}
389
         */
390
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
391
            return instrumentedType;
1✔
392
        }
393

394
        /**
395
         * {@inheritDoc}
396
         */
397
        public Implementation withAssigner(Assigner assigner, Assigner.Typing typing) {
398
            return new ForThisValue(assigner, typing);
×
399
        }
400

401
        /**
402
         * A byte code appender for returning {@code this}.
403
         */
404
        @HashCodeAndEqualsPlugin.Enhance
405
        protected static class Appender implements ByteCodeAppender {
406

407
            /**
408
             * The instrumented type.
409
             */
410
            private final TypeDescription instrumentedType;
411

412
            /**
413
             * Creates a new byte code appender for returning {@code this}.
414
             *
415
             * @param instrumentedType The instrumented type.
416
             */
417
            protected Appender(TypeDescription instrumentedType) {
1✔
418
                this.instrumentedType = instrumentedType;
1✔
419
            }
1✔
420

421
            /**
422
             * {@inheritDoc}
423
             */
424
            public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
425
                if (instrumentedMethod.isStatic() || !instrumentedType.isAssignableTo(instrumentedMethod.getReturnType().asErasure())) {
1✔
426
                    throw new IllegalStateException("Cannot return 'this' from " + instrumentedMethod);
1✔
427
                }
428
                return new ByteCodeAppender.Simple(
1✔
429
                        MethodVariableAccess.loadThis(),
1✔
430
                        MethodReturn.REFERENCE
431
                ).apply(methodVisitor, implementationContext, instrumentedMethod);
1✔
432
            }
433
        }
434
    }
435

436
    /**
437
     * A fixed value implementation that returns a method's argument.
438
     */
439
    @HashCodeAndEqualsPlugin.Enhance
440
    protected static class ForArgument extends FixedValue implements AssignerConfigurable, ByteCodeAppender {
441

442
        /**
443
         * The argument index.
444
         */
445
        private final int index;
446

447
        /**
448
         * Creates a new fixed value implementation that returns a method's argument.
449
         *
450
         * @param index The argument's index.
451
         */
452
        protected ForArgument(int index) {
453
            this(Assigner.DEFAULT, Assigner.Typing.STATIC, index);
1✔
454
        }
1✔
455

456
        /**
457
         * Creates a new fixed value implementation that returns a method's argument.
458
         *
459
         * @param assigner The assigner to use for assigning the fixed value to the return type of the
460
         *                 instrumented value.
461
         * @param typing   Indicates if dynamic type castings should be attempted for incompatible assignments.
462
         * @param index    The argument's index.
463
         */
464
        private ForArgument(Assigner assigner, Assigner.Typing typing, int index) {
465
            super(assigner, typing);
1✔
466
            this.index = index;
1✔
467
        }
1✔
468

469
        /**
470
         * {@inheritDoc}
471
         */
472
        public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
473
            if (instrumentedMethod.getParameters().size() <= index) {
1✔
474
                throw new IllegalStateException(instrumentedMethod + " does not define a parameter with index " + index);
1✔
475
            }
476
            ParameterDescription parameterDescription = instrumentedMethod.getParameters().get(index);
1✔
477
            StackManipulation stackManipulation = new StackManipulation.Compound(
1✔
478
                    MethodVariableAccess.load(parameterDescription),
1✔
479
                    assigner.assign(parameterDescription.getType(), instrumentedMethod.getReturnType(), typing),
1✔
480
                    MethodReturn.of(instrumentedMethod.getReturnType())
1✔
481
            );
482
            if (!stackManipulation.isValid()) {
1✔
483
                throw new IllegalStateException("Cannot assign " + instrumentedMethod.getReturnType() + " to " + parameterDescription);
1✔
484
            }
485
            return new Size(stackManipulation.apply(methodVisitor, implementationContext).getMaximalSize(), instrumentedMethod.getStackSize());
1✔
486
        }
487

488
        /**
489
         * {@inheritDoc}
490
         */
491
        public ByteCodeAppender appender(Target implementationTarget) {
492
            return this;
1✔
493
        }
494

495
        /**
496
         * {@inheritDoc}
497
         */
498
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
499
            return instrumentedType;
1✔
500
        }
501

502
        /**
503
         * {@inheritDoc}
504
         */
505
        public Implementation withAssigner(Assigner assigner, Assigner.Typing typing) {
506
            return new ForArgument(assigner, typing, index);
×
507
        }
508
    }
509

510
    /**
511
     * A fixed value implementation that represents its fixed value as a constant pool value or a byte code instruction.
512
     */
513
    @HashCodeAndEqualsPlugin.Enhance
514
    protected static class ForConstantValue extends FixedValue implements AssignerConfigurable, ByteCodeAppender {
515

516
        /**
517
         * The stack manipulation which is responsible for loading the fixed value onto the operand stack.
518
         */
519
        private final StackManipulation valueLoadInstruction;
520

521
        /**
522
         * The type of the fixed value.
523
         */
524
        private final TypeDescription loadedType;
525

526
        /**
527
         * Creates a new constant pool fixed value implementation.
528
         *
529
         * @param valueLoadInstruction The instruction that is responsible for loading the constant pool value onto the
530
         *                             operand stack.
531
         * @param loadedType           A type description representing the loaded type.
532
         */
533
        protected ForConstantValue(StackManipulation valueLoadInstruction, Class<?> loadedType) {
534
            this(valueLoadInstruction, TypeDescription.ForLoadedType.of(loadedType));
×
535
        }
×
536

537
        /**
538
         * Creates a new constant pool fixed value implementation.
539
         *
540
         * @param valueLoadInstruction The instruction that is responsible for loading the constant pool value onto the
541
         *                             operand stack.
542
         * @param loadedType           A type description representing the loaded type.
543
         */
544
        protected ForConstantValue(StackManipulation valueLoadInstruction, TypeDescription loadedType) {
545
            this(Assigner.DEFAULT, Assigner.Typing.STATIC, valueLoadInstruction, loadedType);
1✔
546
        }
1✔
547

548
        /**
549
         * Creates a new constant pool fixed value implementation.
550
         *
551
         * @param valueLoadInstruction The instruction that is responsible for loading the constant pool value onto the
552
         *                             operand stack.
553
         * @param loadedType           A type description representing the loaded type.
554
         * @param assigner             The assigner to use for assigning the fixed value to the return type of the
555
         *                             instrumented value.
556
         * @param typing               Indicates if dynamic type castings should be attempted for incompatible assignments.
557
         */
558
        private ForConstantValue(Assigner assigner, Assigner.Typing typing, StackManipulation valueLoadInstruction, TypeDescription loadedType) {
559
            super(assigner, typing);
1✔
560
            this.valueLoadInstruction = valueLoadInstruction;
1✔
561
            this.loadedType = loadedType;
1✔
562
        }
1✔
563

564
        /**
565
         * {@inheritDoc}
566
         */
567
        public Implementation withAssigner(Assigner assigner, Assigner.Typing typing) {
568
            return new ForConstantValue(assigner, typing, valueLoadInstruction, loadedType);
1✔
569
        }
570

571
        /**
572
         * {@inheritDoc}
573
         */
574
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
575
            return instrumentedType;
1✔
576
        }
577

578
        /**
579
         * {@inheritDoc}
580
         */
581
        public ByteCodeAppender appender(Target implementationTarget) {
582
            return this;
1✔
583
        }
584

585
        /**
586
         * {@inheritDoc}
587
         */
588
        public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
589
            return apply(methodVisitor, implementationContext, instrumentedMethod, loadedType.asGenericType(), valueLoadInstruction);
1✔
590
        }
591
    }
592

593
    /**
594
     * A fixed value implementation that represents its fixed value as a static field of the instrumented class.
595
     */
596
    @HashCodeAndEqualsPlugin.Enhance
597
    protected static class ForValue extends FixedValue implements AssignerConfigurable {
598

599
        /**
600
         * The prefix of the static field that is created for storing the fixed value.
601
         */
602
        private static final String PREFIX = "value";
603

604
        /**
605
         * The name of the field in which the fixed value is stored.
606
         */
607
        private final String name;
608

609
        /**
610
         * The value that is to be stored in the static field.
611
         */
612
        private final Object value;
613

614
        /**
615
         * Creates a new static field fixed value implementation.
616
         *
617
         * @param value The fixed value to be returned.
618
         * @param name  The name of the field for storing the fixed value.
619
         */
620
        protected ForValue(Object value, String name) {
621
            this(Assigner.DEFAULT, Assigner.Typing.STATIC, value, name);
1✔
622
        }
1✔
623

624
        /**
625
         * Creates a new static field fixed value implementation.
626
         *
627
         * @param value    The fixed value to be returned.
628
         * @param name     The name of the field for storing the fixed value.
629
         * @param assigner The assigner to use for assigning the fixed value to the return type of the
630
         *                 instrumented value.
631
         * @param typing   Indicates if dynamic type castings should be attempted for incompatible assignments.
632
         */
633
        private ForValue(Assigner assigner, Assigner.Typing typing, Object value, String name) {
634
            super(assigner, typing);
1✔
635
            this.name = name;
1✔
636
            this.value = value;
1✔
637
        }
1✔
638

639
        /**
640
         * {@inheritDoc}
641
         */
642
        public Implementation withAssigner(Assigner assigner, Assigner.Typing typing) {
643
            return new ForValue(assigner, typing, value, name);
×
644
        }
645

646
        /**
647
         * {@inheritDoc}
648
         */
649
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
650
            return instrumentedType.withAuxiliaryField(new FieldDescription.Token(name,
1✔
651
                    Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_VOLATILE | Opcodes.ACC_SYNTHETIC,
652
                    TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(value.getClass())), value);
1✔
653
        }
654

655
        /**
656
         * {@inheritDoc}
657
         */
658
        public ByteCodeAppender appender(Target implementationTarget) {
659
            return new StaticFieldByteCodeAppender(implementationTarget.getInstrumentedType());
1✔
660
        }
661

662
        /**
663
         * A byte code appender for returning the fixed value that was stored in a static field.
664
         */
665
        @HashCodeAndEqualsPlugin.Enhance
666
        private class StaticFieldByteCodeAppender implements ByteCodeAppender {
667

668
            /**
669
             * The stack manipulation that loads the fixed value onto the operand stack.
670
             */
671
            private final StackManipulation fieldGetAccess;
672

673
            /**
674
             * Creates a new byte code appender for returning a value of a static field from an instrumented method.
675
             *
676
             * @param instrumentedType The instrumented type that is subject of the instrumentation.
677
             */
678
            private StaticFieldByteCodeAppender(TypeDescription instrumentedType) {
1✔
679
                fieldGetAccess = FieldAccess.forField(instrumentedType.getDeclaredFields().filter((named(name))).getOnly()).read();
1✔
680
            }
1✔
681

682
            /**
683
             * {@inheritDoc}
684
             */
685
            public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
686
                return ForValue.this.apply(methodVisitor,
1✔
687
                        implementationContext,
688
                        instrumentedMethod,
689
                        TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(value.getClass()),
1✔
690
                        fieldGetAccess);
691
            }
692
        }
693
    }
694
}
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