2020
2121import com .google .common .base .Function ;
2222import com .google .common .base .Functions ;
23+ import com .tngtech .archunit .core .domain .JavaClass ;
2324import com .tngtech .archunit .core .domain .JavaClassDescriptor ;
2425import com .tngtech .archunit .core .domain .JavaType ;
2526import com .tngtech .archunit .core .domain .JavaTypeVariable ;
3637import org .slf4j .LoggerFactory ;
3738
3839import static com .google .common .base .Functions .compose ;
40+ import static com .tngtech .archunit .core .domain .DomainObjectCreationContext .createGenericArrayType ;
3941import static com .tngtech .archunit .core .importer .ClassFileProcessor .ASM_API_VERSION ;
4042
4143class JavaGenericTypeImporter {
@@ -109,12 +111,12 @@ public void visitTypeArgument() {
109111 @ Override
110112 public void visitTypeVariable (String name ) {
111113 log .trace ("Encountered upper bound for {}: Type variable {}" , currentType .getName (), name );
112- currentType .addBound (new ReferenceCreationProcess (name ));
114+ currentType .addBound (new ReferenceCreationProcess (name , ReferenceCreationProcess . JavaTypeVariableFinisher . IDENTITY ));
113115 }
114116
115117 @ Override
116118 public SignatureVisitor visitTypeArgument (char wildcard ) {
117- return TypeArgumentProcessor .create (wildcard , currentBound , Functions .<JavaClassDescriptor >identity ());
119+ return TypeArgumentProcessor .create (wildcard , currentBound , Functions .<JavaClassDescriptor >identity (), ReferenceCreationProcess . JavaTypeVariableFinisher . IDENTITY );
118120 }
119121 }
120122 }
@@ -134,13 +136,19 @@ public JavaType finish(Iterable<JavaTypeVariable> allTypeParametersInContext, Cl
134136
135137 private static class ReferenceCreationProcess implements JavaTypeCreationProcess {
136138 private final String typeVariableName ;
139+ private final JavaTypeVariableFinisher finisher ;
137140
138- ReferenceCreationProcess (String typeVariableName ) {
141+ ReferenceCreationProcess (String typeVariableName , JavaTypeVariableFinisher finisher ) {
139142 this .typeVariableName = typeVariableName ;
143+ this .finisher = finisher ;
140144 }
141145
142146 @ Override
143147 public JavaType finish (Iterable <JavaTypeVariable > allTypeParametersInContext , ClassesByTypeName classes ) {
148+ return finisher .finish (createTypeVariable (allTypeParametersInContext , classes ), classes );
149+ }
150+
151+ private JavaType createTypeVariable (Iterable <JavaTypeVariable > allTypeParametersInContext , ClassesByTypeName classes ) {
144152 for (JavaTypeVariable existingTypeVariable : allTypeParametersInContext ) {
145153 if (existingTypeVariable .getName ().equals (typeVariableName )) {
146154 return existingTypeVariable ;
@@ -149,6 +157,38 @@ public JavaType finish(Iterable<JavaTypeVariable> allTypeParametersInContext, Cl
149157 // type variables can be missing from the import context -> create a simple unbound type variable since we have no more information
150158 return new JavaTypeParameterBuilder (typeVariableName ).build (classes );
151159 }
160+
161+ abstract static class JavaTypeVariableFinisher {
162+ abstract JavaType finish (JavaType input , ClassesByTypeName classes );
163+
164+ abstract String getFinishedName (String name );
165+
166+ JavaTypeVariableFinisher after (final JavaTypeVariableFinisher other ) {
167+ return new JavaTypeVariableFinisher () {
168+ @ Override
169+ JavaType finish (JavaType input , ClassesByTypeName classes ) {
170+ return JavaTypeVariableFinisher .this .finish (other .finish (input , classes ), classes );
171+ }
172+
173+ @ Override
174+ String getFinishedName (String name ) {
175+ return JavaTypeVariableFinisher .this .getFinishedName (other .getFinishedName (name ));
176+ }
177+ };
178+ }
179+
180+ static JavaTypeVariableFinisher IDENTITY = new JavaTypeVariableFinisher () {
181+ @ Override
182+ JavaType finish (JavaType input , ClassesByTypeName classes ) {
183+ return input ;
184+ }
185+
186+ @ Override
187+ String getFinishedName (String name ) {
188+ return name ;
189+ }
190+ };
191+ }
152192 }
153193
154194 private static class TypeArgumentProcessor extends SignatureVisitor {
@@ -158,18 +198,37 @@ public JavaClassDescriptor apply(JavaClassDescriptor input) {
158198 return input .toArrayDescriptor ();
159199 }
160200 };
201+ private static final ReferenceCreationProcess .JavaTypeVariableFinisher GENERIC_ARRAY_CREATOR = new ReferenceCreationProcess .JavaTypeVariableFinisher () {
202+ @ Override
203+ public JavaType finish (JavaType componentType , ClassesByTypeName classes ) {
204+ JavaClassDescriptor erasureType = JavaClassDescriptor .From .javaClass (componentType .toErasure ()).toArrayDescriptor ();
205+ JavaClass erasure = classes .get (erasureType .getFullyQualifiedClassName ());
206+ return createGenericArrayType (componentType , erasure );
207+ }
208+
209+ @ Override
210+ String getFinishedName (String name ) {
211+ return name + "[]" ;
212+ }
213+ };
161214
162215 private final TypeArgumentType typeArgumentType ;
163216 private final JavaParameterizedTypeBuilder parameterizedType ;
164217 private final Function <JavaClassDescriptor , JavaClassDescriptor > typeMapping ;
218+ private final ReferenceCreationProcess .JavaTypeVariableFinisher typeVariableFinisher ;
165219
166220 private JavaParameterizedTypeBuilder currentTypeArgument ;
167221
168- TypeArgumentProcessor (TypeArgumentType typeArgumentType , JavaParameterizedTypeBuilder parameterizedType , Function <JavaClassDescriptor , JavaClassDescriptor > typeMapping ) {
222+ TypeArgumentProcessor (
223+ TypeArgumentType typeArgumentType ,
224+ JavaParameterizedTypeBuilder parameterizedType ,
225+ Function <JavaClassDescriptor , JavaClassDescriptor > typeMapping ,
226+ ReferenceCreationProcess .JavaTypeVariableFinisher typeVariableFinisher ) {
169227 super (ASM_API_VERSION );
170228 this .typeArgumentType = typeArgumentType ;
171229 this .parameterizedType = parameterizedType ;
172230 this .typeMapping = typeMapping ;
231+ this .typeVariableFinisher = typeVariableFinisher ;
173232 }
174233
175234 @ Override
@@ -188,28 +247,35 @@ public void visitTypeArgument() {
188247
189248 @ Override
190249 public void visitTypeVariable (String name ) {
191- log .trace ("Encountered {} for {}: Type variable {}" , typeArgumentType .description , parameterizedType .getTypeName (), name );
192- typeArgumentType .addTypeArgumentToBuilder (parameterizedType , new ReferenceCreationProcess (name ));
250+ if (log .isTraceEnabled ()) {
251+ log .trace ("Encountered {} for {}: Type variable {}" , typeArgumentType .description , parameterizedType .getTypeName (), typeVariableFinisher .getFinishedName (name ));
252+ }
253+ typeArgumentType .addTypeArgumentToBuilder (parameterizedType , new ReferenceCreationProcess (name , typeVariableFinisher ));
193254 }
194255
195256 @ Override
196257 public SignatureVisitor visitTypeArgument (char wildcard ) {
197- return TypeArgumentProcessor .create (wildcard , currentTypeArgument , typeMapping );
258+ return TypeArgumentProcessor .create (wildcard , currentTypeArgument , typeMapping , typeVariableFinisher );
198259 }
199260
200261 @ Override
201262 public SignatureVisitor visitArrayType () {
202- return new TypeArgumentProcessor (typeArgumentType , parameterizedType , compose (typeMapping , TO_ARRAY_TYPE ));
263+ return new TypeArgumentProcessor (typeArgumentType , parameterizedType , compose (typeMapping , TO_ARRAY_TYPE ), typeVariableFinisher . after ( GENERIC_ARRAY_CREATOR ) );
203264 }
204265
205- static TypeArgumentProcessor create (char identifier , JavaParameterizedTypeBuilder parameterizedType , Function <JavaClassDescriptor , JavaClassDescriptor > typeMapping ) {
266+ static TypeArgumentProcessor create (
267+ char identifier ,
268+ JavaParameterizedTypeBuilder parameterizedType ,
269+ Function <JavaClassDescriptor , JavaClassDescriptor > typeMapping ,
270+ ReferenceCreationProcess .JavaTypeVariableFinisher typeVariableFinisher ) {
271+
206272 switch (identifier ) {
207273 case '=' :
208- return new TypeArgumentProcessor (PARAMETERIZED_TYPE , parameterizedType , typeMapping );
274+ return new TypeArgumentProcessor (PARAMETERIZED_TYPE , parameterizedType , typeMapping , typeVariableFinisher );
209275 case '+' :
210- return new TypeArgumentProcessor (WILDCARD_WITH_UPPER_BOUND , parameterizedType , typeMapping );
276+ return new TypeArgumentProcessor (WILDCARD_WITH_UPPER_BOUND , parameterizedType , typeMapping , typeVariableFinisher );
211277 case '-' :
212- return new TypeArgumentProcessor (WILDCARD_WITH_LOWER_BOUND , parameterizedType , typeMapping );
278+ return new TypeArgumentProcessor (WILDCARD_WITH_LOWER_BOUND , parameterizedType , typeMapping , typeVariableFinisher );
213279 default :
214280 throw new IllegalStateException (String .format ("Cannot handle asm type argument identifier '%s'" , identifier ));
215281 }
0 commit comments