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.field.FieldDescription;
20 import net.bytebuddy.description.method.MethodDescription;
21 import net.bytebuddy.description.method.MethodList;
22 import net.bytebuddy.description.method.ParameterDescription;
23 import net.bytebuddy.description.type.TypeDescription;
24 import net.bytebuddy.implementation.Implementation;
25 import net.bytebuddy.implementation.bind.MethodDelegationBinder;
26 import net.bytebuddy.implementation.bytecode.StackManipulation;
27 import net.bytebuddy.implementation.bytecode.assign.Assigner;
28 import net.bytebuddy.implementation.bytecode.member.FieldAccess;
29 import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
30
31 import java.lang.annotation.*;
32
33 import static net.bytebuddy.matcher.ElementMatchers.named;
34
35 /**
36  * <p>
37  * Assigns the value of a field of the instrumented type to the annotated parameter. For a binding to be valid,
38  * the instrumented type must be able to access a field of the given name. Also, the parameter's type must be
39  * assignable to the given field. For attempting a type casting, the {@link RuntimeType} annotation can be
40  * applied to the parameter.
41  * </p>
42  * <p>
43  * Setting {@link FieldValue#value()} is optional. If the value is not set, the field value attempts to bind a setter's
44  * or getter's field if the intercepted method is an accessor method. Otherwise, the binding renders the target method
45  * to be an illegal candidate for binding.
46  * </p>
47  *
48  * @see net.bytebuddy.implementation.MethodDelegation
49  * @see net.bytebuddy.implementation.bind.annotation.TargetMethodAnnotationDrivenBinder
50  * @see net.bytebuddy.implementation.bind.annotation.RuntimeType
51  */

52 @Documented
53 @Retention(RetentionPolicy.RUNTIME)
54 @Target(ElementType.PARAMETER)
55 public @interface FieldValue {
56
57     /**
58      * The name of the field to be accessed.
59      *
60      * @return The name of the field.
61      */

62     String value() default TargetMethodAnnotationDrivenBinder.ParameterBinder.ForFieldBinding.BEAN_PROPERTY;
63
64     /**
65      * Defines the type on which the field is declared. If this value is not set, the most specific type's field is read,
66      * if two fields with the same name exist in the same type hierarchy.
67      *
68      * @return The type that declares the accessed field.
69      */

70     Class<?> declaringType() default void.class;
71
72     /**
73      * Binds a {@link FieldValue} annotation.
74      */

75     enum Binder implements TargetMethodAnnotationDrivenBinder.ParameterBinder<FieldValue> {
76
77         /**
78          * The singleton instance.
79          */

80         INSTANCE(new Delegate());
81
82         /**
83          * The annotation method that for the defining type.
84          */

85         private static final MethodDescription.InDefinedShape DECLARING_TYPE;
86
87         /**
88          * The annotation method for the field's name.
89          */

90         private static final MethodDescription.InDefinedShape FIELD_NAME;
91
92         /*
93          * Initializes the methods of the annotation that is read by this binder.
94          */

95         static {
96             MethodList<MethodDescription.InDefinedShape> methodList = TypeDescription.ForLoadedType.of(FieldValue.class).getDeclaredMethods();
97             DECLARING_TYPE = methodList.filter(named("declaringType")).getOnly();
98             FIELD_NAME = methodList.filter(named("value")).getOnly();
99         }
100
101         /**
102          * A delegate parameter binder responsible for binding the parameter.
103          */

104         private final TargetMethodAnnotationDrivenBinder.ParameterBinder<FieldValue> delegate;
105
106         /**
107          * Creates a new binder for a {@link FieldValue}.
108          *
109          * @param delegate A delegate parameter binder responsible for binding the parameter.
110          */

111         Binder(TargetMethodAnnotationDrivenBinder.ParameterBinder<FieldValue> delegate) {
112             this.delegate = delegate;
113         }
114
115         /**
116          * {@inheritDoc}
117          */

118         public Class<FieldValue> getHandledType() {
119             return delegate.getHandledType();
120         }
121
122         /**
123          * {@inheritDoc}
124          */

125         public MethodDelegationBinder.ParameterBinding<?> bind(AnnotationDescription.Loadable<FieldValue> annotation,
126                                                                MethodDescription source,
127                                                                ParameterDescription target,
128                                                                Implementation.Target implementationTarget,
129                                                                Assigner assigner,
130                                                                Assigner.Typing typing) {
131             return delegate.bind(annotation, source, target, implementationTarget, assigner, typing);
132         }
133
134         /**
135          * A delegate implementation for the {@link FieldValue.Binder}.
136          */

137         protected static class Delegate extends ForFieldBinding<FieldValue> {
138
139             /**
140              * {@inheritDoc}
141              */

142             public Class<FieldValue> getHandledType() {
143                 return FieldValue.class;
144             }
145
146             @Override
147             protected String fieldName(AnnotationDescription.Loadable<FieldValue> annotation) {
148                 return annotation.getValue(FIELD_NAME).resolve(String.class);
149             }
150
151             @Override
152             protected TypeDescription declaringType(AnnotationDescription.Loadable<FieldValue> annotation) {
153                 return annotation.getValue(DECLARING_TYPE).resolve(TypeDescription.class);
154             }
155
156             @Override
157             protected MethodDelegationBinder.ParameterBinding<?> bind(FieldDescription fieldDescription,
158                                                                       AnnotationDescription.Loadable<FieldValue> annotation,
159                                                                       MethodDescription source,
160                                                                       ParameterDescription target,
161                                                                       Implementation.Target implementationTarget,
162                                                                       Assigner assigner) {
163                 StackManipulation stackManipulation = new StackManipulation.Compound(
164                         fieldDescription.isStatic()
165                                 ? StackManipulation.Trivial.INSTANCE
166                                 : MethodVariableAccess.loadThis(),
167                         FieldAccess.forField(fieldDescription).read(),
168                         assigner.assign(fieldDescription.getType(), target.getType(), RuntimeType.Verifier.check(target))
169                 );
170                 return stackManipulation.isValid()
171                         ? new MethodDelegationBinder.ParameterBinding.Anonymous(stackManipulation)
172                         : MethodDelegationBinder.ParameterBinding.Illegal.INSTANCE;
173             }
174         }
175     }
176 }
177