1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.di;
20
21 import java.lang.reflect.ParameterizedType;
22 import java.lang.reflect.Type;
23 import java.util.Objects;
24
25 import org.apache.maven.api.annotations.Nullable;
26 import org.apache.maven.di.impl.ReflectionUtils;
27 import org.apache.maven.di.impl.Types;
28 import org.apache.maven.di.impl.Utils;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 public abstract class Key<T> {
46 private final Type type;
47 private final @Nullable Object qualifier;
48
49 private int hash;
50
51 protected Key() {
52 this(null);
53 }
54
55 protected Key(@Nullable Object qualifier) {
56 this.type = Types.simplifyType(getTypeParameter());
57 this.qualifier = qualifier;
58 }
59
60 protected Key(Type type, @Nullable Object qualifier) {
61 this.type = Types.simplifyType(type);
62 this.qualifier = qualifier;
63 }
64
65 static final class KeyImpl<T> extends Key<T> {
66 KeyImpl(Type type, Object qualifier) {
67 super(type, qualifier);
68 }
69 }
70
71 public static <T> Key<T> of(Class<T> type) {
72 return new KeyImpl<>(type, null);
73 }
74
75 public static <T> Key<T> of(Class<T> type, @Nullable Object qualifier) {
76 return new KeyImpl<>(type, qualifier);
77 }
78
79 public static <T> Key<T> ofType(Type type) {
80 return new KeyImpl<>(type, null);
81 }
82
83 public static <T> Key<T> ofType(Type type, @Nullable Object qualifier) {
84 return new KeyImpl<>(type, qualifier);
85 }
86
87 private Type getTypeParameter() {
88
89 Type typeArgument = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
90 Object outerInstance = ReflectionUtils.getOuterClassInstance(this);
91
92 return outerInstance != null
93 ? Types.bind(typeArgument, Types.getAllTypeBindings(outerInstance.getClass()))
94 : typeArgument;
95 }
96
97 public Type getType() {
98 return type;
99 }
100
101
102
103
104
105 @SuppressWarnings("unchecked")
106 public Class<T> getRawType() {
107 return (Class<T>) Types.getRawType(type);
108 }
109
110
111
112
113
114
115 public <U> Key<U> getTypeParameter(int index) {
116 if (type instanceof ParameterizedType) {
117 return new KeyImpl<>(((ParameterizedType) type).getActualTypeArguments()[index], null);
118 }
119 throw new IllegalStateException("Expected type from key " + getDisplayString() + " to be parameterized");
120 }
121
122 public @Nullable Object getQualifier() {
123 return qualifier;
124 }
125
126
127
128
129
130 public String getDisplayString() {
131 return (qualifier != null ? getQualifierDisplayString() + " " : "") + ReflectionUtils.getDisplayName(type);
132 }
133
134 private String getQualifierDisplayString() {
135 if (qualifier instanceof String s) {
136 return s.isEmpty() ? "@Named" : "@Named(\"" + s + "\")";
137 }
138 String s = Utils.getDisplayString(qualifier);
139 return s;
140 }
141
142 @Override
143 public boolean equals(Object o) {
144 if (this == o) {
145 return true;
146 }
147 if (!(o instanceof Key<?>)) {
148 return false;
149 }
150 Key<?> that = (Key<?>) o;
151 return type.equals(that.type) && Objects.equals(qualifier, that.qualifier);
152 }
153
154 @Override
155 public int hashCode() {
156 int hashCode = hash;
157 if (hashCode == 0) {
158 hash = 31 * type.hashCode() + (qualifier == null ? 0 : qualifier.hashCode());
159 }
160 return hash;
161 }
162
163 @Override
164 public String toString() {
165 return getDisplayString();
166 }
167 }