@@ -202,9 +202,6 @@ public void addTransformer(@NonNull Transformer.TargetedTransformer t) {
202202 }
203203
204204 public void addTransformer (@ NonNull String s , @ NonNull Transformer t ) {
205- if (!t .shouldTransform (s )) {
206- throw new IllegalArgumentException ("Transformer " + t + " must transform class of name " + s );
207- }
208205 if (classTransformers .get (s ).contains (t )) {
209206 throw new IllegalArgumentException ("Transformer " + t + " has already been added for class " + s );
210207 }
@@ -227,64 +224,73 @@ public Supplier<byte[]> transformJava(@NonNull Supplier<byte[]> data, @NonNull S
227224 if (!shouldTransform (name ))
228225 return data ;
229226
230- CompilationUnit cu ;
231- try {
232- cu = JavaParser .parse (new ByteArrayInputStream (data .get ()));
233- } catch (ParseException e ) {
234- throw new RuntimeException (e );
235- }
236-
237- String packageName = cu .getPackage ().getName ().getName ();
238- for (TypeDeclaration typeDeclaration : cu .getTypes ()) {
239- if (!(typeDeclaration instanceof ClassOrInterfaceDeclaration )) {
240- continue ;
227+ CachingSupplier <ClassOrInterfaceDeclaration > supplier = CachingSupplier .of (() -> {
228+ CompilationUnit cu ;
229+ try {
230+ cu = JavaParser .parse (new ByteArrayInputStream (data .get ()));
231+ } catch (ParseException e ) {
232+ throw new RuntimeException (e );
241233 }
242- val classDeclaration = (ClassOrInterfaceDeclaration ) typeDeclaration ;
243234
244- String shortClassName = classDeclaration .getName ();
245- if ((packageName + '.' + shortClassName ).equalsIgnoreCase (name )) {
246- transformJar (new SourceInfo (classDeclaration ));
235+ String packageName = cu .getPackage ().getName ().getName ();
236+ for (TypeDeclaration typeDeclaration : cu .getTypes ()) {
237+ if (!(typeDeclaration instanceof ClassOrInterfaceDeclaration )) {
238+ continue ;
239+ }
240+ ClassOrInterfaceDeclaration classDeclaration = (ClassOrInterfaceDeclaration ) typeDeclaration ;
241+
242+ String shortClassName = classDeclaration .getName ();
243+ if ((packageName + '.' + shortClassName ).equalsIgnoreCase (name )) {
244+ return classDeclaration ;
245+ }
247246 }
248- }
249247
250- return () -> cu .toString ().getBytes (Charset .forName ("UTF-8" ));
248+ throw new Error ("Couldn't find any class or interface declaration matching expected name " + name );
249+ });
250+
251+ transformClassInfo (new SourceInfo (supplier , name ));
252+
253+ return supplier .isCached () ? () -> supplier .get ().toString ().getBytes (Charset .forName ("UTF-8" )) : data ;
254+
251255 }
252256
253257 public Supplier <byte []> transformClass (@ NonNull Supplier <byte []> data , @ NonNull String name ) {
258+ System .out .println ("Transforming " + name );
254259 if (!shouldTransform (name ))
255260 return data ;
256261
257- ClassNode node = new ClassNode ();
258- ClassReader reader = new ClassReader (data .get ());
259- reader .accept (node , ClassReader .EXPAND_FRAMES );
262+ Holder <ClassReader > readerHolder = new Holder <>();
263+ CachingSupplier <ClassNode > supplier = CachingSupplier .of (() -> {
264+ ClassNode node = new ClassNode ();
265+ ClassReader reader = new ClassReader (data .get ());
266+ reader .accept (node , ClassReader .EXPAND_FRAMES );
260267
261- transformJar (new ByteCodeInfo (node ));
268+ readerHolder .value = reader ;
269+
270+ return node ;
271+ });
262272
263- ClassWriter classWriter = new ClassWriter (reader , 0 );
264- node .accept (classWriter );
265- return classWriter ::toByteArray ;
273+ transformClassInfo (new ByteCodeInfo (supplier , name ));
274+
275+ if (!supplier .isCached ())
276+ return data ;
277+
278+ return () -> {
279+ ClassWriter classWriter = new ClassWriter (readerHolder .value , 0 );
280+ supplier .get ().accept (classWriter );
281+ return classWriter .toByteArray ();
282+ };
266283 }
267284
268- private void transformJar (ClassInfo editor ) {
269- val name = editor .getName ();
285+ private void transformClassInfo (ClassInfo editor ) {
270286 transformers .forEach ((x ) -> {
271- if (x .shouldTransform (name )) {
272- x .transform (editor );
273- }
287+ x .transform (editor );
274288 });
275- classTransformers .get (name ).forEach ((it ) -> it .transform (editor ));
289+ classTransformers .get (editor . getName () ).forEach ((it ) -> it .transform (editor ));
276290 }
277291
278292 private boolean shouldTransform (String className ) {
279- if (!classTransformers .get (className ).isEmpty ())
280- return true ;
281-
282- for (Transformer transformer : transformers ) {
283- if (transformer .shouldTransform (className ))
284- return true ;
285- }
286-
287- return false ;
293+ return !transformers .isEmpty () || !classTransformers .get (className ).isEmpty ();
288294 }
289295
290296 private Supplier <byte []> transformBytes (String relativeName , Supplier <byte []> dataSupplier ) {
@@ -342,4 +348,41 @@ public String toString() {
342348 return map .toString ();
343349 }
344350 }
351+
352+ @ Data
353+ private static class CachingSupplier <T > implements Supplier <T > {
354+ @ NonNull
355+ private final Supplier <T > wrapped ;
356+ private transient T value ;
357+
358+ protected CachingSupplier (Supplier <T > wrapped ) {
359+ this .wrapped = wrapped ;
360+ }
361+
362+ public static <T > CachingSupplier <T > of (Supplier <T > wrapped ) {
363+ return new CachingSupplier <>(wrapped );
364+ }
365+
366+ @ Override
367+ public T get () {
368+ T value = this .value ;
369+
370+ if (value == null ) {
371+ synchronized (this ) {
372+ if (this .value == null )
373+ this .value = value = Objects .requireNonNull (wrapped .get ());
374+ }
375+ }
376+
377+ return value ;
378+ }
379+
380+ public boolean isCached () {
381+ return value != null ;
382+ }
383+ }
384+
385+ private static class Holder <T > {
386+ public T value ;
387+ }
345388}
0 commit comments