1
1
package org .kohsuke .github ;
2
2
3
3
import com .tngtech .archunit .base .DescribedPredicate ;
4
- import com .tngtech .archunit .core .domain .JavaAnnotation ;
5
- import com .tngtech .archunit .core .domain .JavaCall ;
6
- import com .tngtech .archunit .core .domain .JavaClass ;
7
- import com .tngtech .archunit .core .domain .JavaClasses ;
4
+ import com .tngtech .archunit .core .domain .*;
8
5
import com .tngtech .archunit .core .domain .properties .HasName ;
9
6
import com .tngtech .archunit .core .domain .properties .HasOwner ;
10
7
import com .tngtech .archunit .core .importer .ClassFileImporter ;
11
8
import com .tngtech .archunit .core .importer .ImportOption ;
9
+ import com .tngtech .archunit .lang .ArchCondition ;
12
10
import com .tngtech .archunit .lang .ArchRule ;
11
+ import org .apache .commons .io .IOUtils ;
12
+ import org .apache .commons .lang3 .StringUtils ;
13
+ import org .apache .commons .lang3 .builder .ReflectionToStringBuilder ;
14
+ import org .apache .commons .lang3 .builder .ToStringBuilder ;
15
+ import org .apache .commons .lang3 .builder .ToStringStyle ;
13
16
import org .junit .BeforeClass ;
14
17
import org .junit .Test ;
15
18
19
+ import java .io .Closeable ;
20
+ import java .io .InputStream ;
21
+ import java .io .Reader ;
22
+ import java .lang .reflect .Field ;
23
+ import java .nio .charset .Charset ;
24
+
25
+ import static com .google .common .base .Preconditions .checkNotNull ;
16
26
import static com .tngtech .archunit .core .domain .JavaCall .Predicates .target ;
17
27
import static com .tngtech .archunit .core .domain .JavaClass .Predicates .resideInAPackage ;
28
+ import static com .tngtech .archunit .core .domain .JavaClass .Predicates .type ;
29
+ import static com .tngtech .archunit .core .domain .JavaClass .namesOf ;
18
30
import static com .tngtech .archunit .core .domain .properties .HasName .Predicates .name ;
19
31
import static com .tngtech .archunit .core .domain .properties .HasName .Predicates .nameContaining ;
32
+ import static com .tngtech .archunit .core .domain .properties .HasOwner .Predicates .With .owner ;
33
+ import static com .tngtech .archunit .core .domain .properties .HasParameterTypes .Predicates .rawParameterTypes ;
20
34
import static com .tngtech .archunit .lang .conditions .ArchConditions .*;
21
35
import static com .tngtech .archunit .lang .syntax .ArchRuleDefinition .classes ;
22
36
import static com .tngtech .archunit .lang .syntax .ArchRuleDefinition .fields ;
@@ -139,45 +153,88 @@ public void testRequireUseOfAssertThat() {
139
153
@ Test
140
154
public void testRequireUseOfOnlySpecificApacheCommons () {
141
155
142
- final DescribedPredicate <JavaCall <?>> approvedStringUtilsMethods = target (
143
- HasOwner .Predicates .With .<JavaClass >owner (name ("org.apache.commons.lang3.StringUtils" )))
144
- .and (target (name ("prependIfMissing" ).or (name ("isBlank" ))
145
- .or (name ("isEmpty" ))
146
- .or (name ("equals" ))
147
- .or (name ("capitalize" ))
148
- .or (name ("join" ))
149
- .or (name ("defaultString" ))));
150
- final DescribedPredicate <JavaCall <?>> approvedToStringBuilderMethods = target (
151
- HasOwner .Predicates .With .<JavaClass >owner (name ("org.apache.commons.lang3.builder.ToStringBuilder" )))
152
- .and (target (name ("toString" ).or (name ("append" ))
153
- .or (name ("isEmpty" ))
154
- .or (name ("equals" ))
155
- .or (name ("capitalize" ))));
156
- final DescribedPredicate <JavaCall <?>> approvedToStringStyleMethods = target (
157
- HasOwner .Predicates .With .<JavaClass >owner (name ("org.apache.commons.lang3.builder.ToStringStyle" )))
158
- .and (target (name ("append" )));
159
- final DescribedPredicate <JavaCall <?>> approvedReflectionStringBuilderMethods = target (HasOwner .Predicates .With
160
- .<JavaClass >owner (name ("org.apache.commons.lang3.builder.ReflectionToStringBuilder" )))
161
- .and (target (name ("accept" )));
162
-
163
- final DescribedPredicate <JavaCall <?>> approvedIOUtilsMethods = target (
164
- HasOwner .Predicates .With .<JavaClass >owner (name ("org.apache.commons.io.IOUtils" )))
165
- .and (target (name ("closeQuietly" ).or (name ("toString" )).or (name ("toByteArray" ))));
166
-
167
- final DescribedPredicate <JavaCall <?>> approvedApacheCommonsMethods = approvedStringUtilsMethods
168
- .or (approvedToStringBuilderMethods )
169
- .or (approvedToStringStyleMethods )
170
- .or (approvedReflectionStringBuilderMethods )
171
- .or (approvedIOUtilsMethods );
172
-
173
156
final ArchRule onlyApprovedApacheCommonsLang3Methods = classes ()
174
- .should (not (callMethodWhere (
175
- target (HasOwner .Predicates .With .<JavaClass >owner (resideInAPackage ("org.apache.commons.." )))
176
- .and (DescribedPredicate .not (approvedApacheCommonsMethods )))))
157
+ .should (notCallMethodsInPackageUnless ("org.apache.commons.." ,
158
+ // unless it is one of these methods
159
+ targetMethodIs (StringUtils .class , "capitalize" , String .class ),
160
+ targetMethodIs (StringUtils .class , "defaultString" , String .class , String .class ),
161
+ targetMethodIs (StringUtils .class , "equals" , CharSequence .class , CharSequence .class ),
162
+ targetMethodIs (StringUtils .class , "isBlank" , CharSequence .class ),
163
+ targetMethodIs (StringUtils .class , "isEmpty" , CharSequence .class ),
164
+ targetMethodIs (StringUtils .class , "join" , Iterable .class , String .class ),
165
+ targetMethodIs (StringUtils .class ,
166
+ "prependIfMissing" ,
167
+ String .class ,
168
+ CharSequence .class ,
169
+ CharSequence [].class ),
170
+ targetMethodIs (ToStringBuilder .class , "toString" ),
171
+ targetMethodIs (ToStringBuilder .class , "append" , String .class , Object .class ),
172
+ targetMethodIs (ToStringBuilder .class , "append" , String .class , long .class ),
173
+ targetMethodIs (ToStringBuilder .class , "append" , String .class , int .class ),
174
+ targetMethodIs (ToStringBuilder .class , "isEmpty" ),
175
+ targetMethodIs (ToStringBuilder .class , "equals" ),
176
+ targetMethodIs (ToStringBuilder .class , "capitalize" ),
177
+ targetMethodIs (ToStringStyle .class ,
178
+ "append" ,
179
+ StringBuffer .class ,
180
+ String .class ,
181
+ Object .class ,
182
+ Boolean .class ),
183
+ targetMethodIs (ReflectionToStringBuilder .class , "accept" , Field .class ),
184
+ targetMethodIs (IOUtils .class , "closeQuietly" , InputStream .class ),
185
+ targetMethodIs (IOUtils .class , "closeQuietly" , Closeable .class ),
186
+ targetMethodIs (IOUtils .class , "toString" , InputStream .class , Charset .class ),
187
+ targetMethodIs (IOUtils .class , "toString" , Reader .class ),
188
+ targetMethodIs (IOUtils .class , "toByteArray" , InputStream .class )))
177
189
.because (
178
- "Only commons methods that have been manually verified to be compatible with commons-io:2.4 or earlier and commons-lang3:3.9 or earlier should be used." );
190
+ "Commons methods must be manually verified to be compatible with commons-io:2.4 or earlier and commons-lang3:3.9 or earlier should be used." );
179
191
180
192
onlyApprovedApacheCommonsLang3Methods .check (classFiles );
181
193
}
182
194
195
+ public static ArchCondition <JavaClass > notCallMethodsInPackageUnless (final String packageIdentifier ,
196
+ final DescribedPredicate <JavaCall <?>>... unlessPredicates ) {
197
+ DescribedPredicate <JavaCall <?>> restrictedPackageCalls = target (
198
+ HasOwner .Predicates .With .<JavaClass >owner (resideInAPackage (packageIdentifier )));
199
+
200
+ if (unlessPredicates .length > 0 ) {
201
+ DescribedPredicate <JavaCall <?>> allowed = unlessPredicates [0 ];
202
+ for (int x = 1 ; x < unlessPredicates .length ; x ++) {
203
+ allowed = allowed .or (unlessPredicates [x ]);
204
+ }
205
+ restrictedPackageCalls = unless (restrictedPackageCalls , allowed );
206
+ }
207
+ return not (callMethodWhere (restrictedPackageCalls ));
208
+ }
209
+
210
+ public static DescribedPredicate <JavaCall <?>> targetMethodIs (Class <?> owner ,
211
+ String methodName ,
212
+ Class <?>... parameterTypes ) {
213
+ return JavaCall .Predicates .target (owner (type (owner )))
214
+ .and (JavaCall .Predicates .target (name (methodName )))
215
+ .and (JavaCall .Predicates .target (rawParameterTypes (parameterTypes )))
216
+ .as ("method is %s" ,
217
+ Formatters .formatMethodSimple (owner .getSimpleName (), methodName , namesOf (parameterTypes )));
218
+ }
219
+
220
+ public static <T > DescribedPredicate <T > unless (DescribedPredicate <? super T > first ,
221
+ DescribedPredicate <? super T > second ) {
222
+ return new UnlessPredicate (first , second );
223
+ }
224
+
225
+ private static class UnlessPredicate <T > extends DescribedPredicate <T > {
226
+ private final DescribedPredicate <T > current ;
227
+ private final DescribedPredicate <? super T > other ;
228
+
229
+ UnlessPredicate (DescribedPredicate <T > current , DescribedPredicate <? super T > other ) {
230
+ super (current .getDescription () + " unless " + other .getDescription ());
231
+ this .current = checkNotNull (current );
232
+ this .other = checkNotNull (other );
233
+ }
234
+
235
+ @ Override
236
+ public boolean apply (T input ) {
237
+ return current .apply (input ) && !other .apply (input );
238
+ }
239
+ }
183
240
}
0 commit comments