1 /*
2  * Copyright 2014 - 2020 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.description.annotation.AnnotationDescription;
19 import net.bytebuddy.description.method.MethodDescription;
20 import net.bytebuddy.description.method.ParameterDescription;
21 import net.bytebuddy.description.type.TypeDescription;
22 import net.bytebuddy.implementation.Implementation;
23 import net.bytebuddy.implementation.bind.MethodDelegationBinder;
24 import net.bytebuddy.implementation.bytecode.StackManipulation;
25 import net.bytebuddy.implementation.bytecode.assign.Assigner;
26 import net.bytebuddy.implementation.bytecode.constant.DefaultValue;
27 import net.bytebuddy.implementation.bytecode.constant.NullConstant;
28
29 import java.lang.annotation.*;
30
31 /**
32  * A stub value represents the (boxed) default value of the intercepted method's return type. This value can
33  * only be assigned to a {@link java.lang.Object} parameter. This annotation is useful to conditionally return a
34  * default value from a method when using an {@link java.lang.Object} return type in combination with the
35  * {@link net.bytebuddy.implementation.bind.annotation.RuntimeType} annotation. The value is either representing
36  * {@code nullif a method returns a reference type or {@code void} or a boxed primitive of the return type
37  * representing the numeric value {@code 0}.
38  *
39  * @see net.bytebuddy.implementation.MethodDelegation
40  * @see net.bytebuddy.implementation.bind.annotation.TargetMethodAnnotationDrivenBinder
41  */

42 @Documented
43 @Retention(RetentionPolicy.RUNTIME)
44 @Target({ElementType.PARAMETER})
45 public @interface StubValue {
46
47     /**
48      * Binds the {@link net.bytebuddy.implementation.bind.annotation.StubValue} annotation.
49      */

50     enum Binder implements TargetMethodAnnotationDrivenBinder.ParameterBinder<StubValue> {
51
52         /**
53          * The singleton instance.
54          */

55         INSTANCE;
56
57         /**
58          * {@inheritDoc}
59          */

60         public Class<StubValue> getHandledType() {
61             return StubValue.class;
62         }
63
64         /**
65          * {@inheritDoc}
66          */

67         public MethodDelegationBinder.ParameterBinding<?> bind(AnnotationDescription.Loadable<StubValue> annotation,
68                                                                MethodDescription source,
69                                                                ParameterDescription target,
70                                                                Implementation.Target implementationTarget,
71                                                                Assigner assigner,
72                                                                Assigner.Typing typing) {
73             if (!target.getType().represents(Object.class)) {
74                 throw new IllegalStateException(target + " uses StubValue annotation on non-Object type");
75             }
76             return new MethodDelegationBinder.ParameterBinding.Anonymous(source.getReturnType().represents(void.class)
77                     ? NullConstant.INSTANCE
78                     : new StackManipulation.Compound(DefaultValue.of(source.getReturnType().asErasure()),
79                     assigner.assign(source.getReturnType(), TypeDescription.Generic.OBJECT, typing)));
80         }
81     }
82 }
83