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.implementation.Implementation;
22 import net.bytebuddy.implementation.bind.MethodDelegationBinder;
23 import net.bytebuddy.implementation.bytecode.StackManipulation;
24 import net.bytebuddy.implementation.bytecode.assign.Assigner;
25 import net.bytebuddy.implementation.bytecode.constant.NullConstant;
26 import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
27
28 import java.lang.annotation.*;
29
30 /**
31 * Parameters that are annotated with this annotation will be assigned a reference to the instrumented object, if
32 * the instrumented method is not static. Otherwise, the method with this parameter annotation will be excluded from
33 * the list of possible binding candidates of the static source method.
34 *
35 * @see net.bytebuddy.implementation.MethodDelegation
36 * @see net.bytebuddy.implementation.bind.annotation.TargetMethodAnnotationDrivenBinder
37 */
38 @Documented
39 @Retention(RetentionPolicy.RUNTIME)
40 @Target(ElementType.PARAMETER)
41 public @interface This {
42
43 /**
44 * Determines if the annotated parameter should be bound to {@code null} when intercepting a {@code static} method.
45 *
46 * @return {@code true} if the annotated parameter should be bound to {@code null} as a fallback.
47 */
48 boolean optional() default false;
49
50 /**
51 * A binder for handling the
52 * {@link net.bytebuddy.implementation.bind.annotation.This}
53 * annotation.
54 *
55 * @see TargetMethodAnnotationDrivenBinder
56 */
57 enum Binder implements TargetMethodAnnotationDrivenBinder.ParameterBinder<This> {
58
59 /**
60 * The singleton instance.
61 */
62 INSTANCE;
63
64 /**
65 * {@inheritDoc}
66 */
67 public Class<This> getHandledType() {
68 return This.class;
69 }
70
71 /**
72 * {@inheritDoc}
73 */
74 public MethodDelegationBinder.ParameterBinding<?> bind(AnnotationDescription.Loadable<This> annotation,
75 MethodDescription source,
76 ParameterDescription target,
77 Implementation.Target implementationTarget,
78 Assigner assigner,
79 Assigner.Typing typing) {
80 if (target.getType().isPrimitive()) {
81 throw new IllegalStateException(target + " uses a primitive type with a @This annotation");
82 } else if (target.getType().isArray()) {
83 throw new IllegalStateException(target + " uses an array type with a @This annotation");
84 } else if (source.isStatic() && !annotation.load().optional()) {
85 return MethodDelegationBinder.ParameterBinding.Illegal.INSTANCE;
86 }
87 return new MethodDelegationBinder.ParameterBinding.Anonymous(source.isStatic()
88 ? NullConstant.INSTANCE
89 : new StackManipulation.Compound(MethodVariableAccess.loadThis(),
90 assigner.assign(implementationTarget.getInstrumentedType().asGenericType(), target.getType(), typing)));
91 }
92 }
93 }
94
95