11package org .javamodularity .moduleplugin .tasks ;
22
33import org .gradle .api .Project ;
4+ import org .gradle .api .Task ;
5+ import org .gradle .api .file .DirectoryProperty ;
46import org .gradle .api .file .DuplicatesStrategy ;
57import org .gradle .api .file .FileCollection ;
68import org .gradle .api .logging .Logger ;
1517import org .javamodularity .moduleplugin .internal .StreamHelper ;
1618
1719import java .io .File ;
20+ import java .lang .reflect .InvocationTargetException ;
21+ import java .lang .reflect .Method ;
1822import java .util .HashSet ;
1923import java .util .List ;
2024import java .util .Optional ;
2125import java .util .Set ;
26+ import java .util .function .Supplier ;
2227import java .util .stream .Stream ;
2328
2429public class MergeClassesHelper {
@@ -38,10 +43,11 @@ public Project project() {
3843 return project ;
3944 }
4045
41- public Stream <AbstractCompile > otherCompileTaskStream () {
46+ public Stream <CompileTaskWrapper > otherCompileTaskStream () {
4247 return otherCompileTaskNameStream ()
43- .map (name -> helper ().findTask (name , AbstractCompile .class ))
44- .flatMap (Optional ::stream );
48+ .map (name -> helper ().findTask (name , Task .class ))
49+ .flatMap (Optional ::stream )
50+ .map (this ::toWrapper );
4551 }
4652
4753 private Stream <String > otherCompileTaskNameStream () {
@@ -52,16 +58,16 @@ private Stream<String> otherCompileTaskNameStream() {
5258 );
5359 }
5460
55- public JavaCompile javaCompileTask () {
56- return helper ().task (JavaPlugin .COMPILE_JAVA_TASK_NAME , JavaCompile .class );
61+ private CompileTaskWrapper javaCompileTask () {
62+ return toWrapper ( helper ().task (JavaPlugin .COMPILE_JAVA_TASK_NAME , JavaCompile .class ) );
5763 }
5864
59- public Stream <AbstractCompile > allCompileTaskStream () {
65+ public Stream <CompileTaskWrapper > allCompileTaskStream () {
6066 return Stream .concat (Stream .of (javaCompileTask ()), otherCompileTaskStream ());
6167 }
6268
6369 public boolean isMergeRequired () {
64- return otherCompileTaskStream ().anyMatch (task -> ! task . getSource (). isEmpty () );
70+ return otherCompileTaskStream ().anyMatch (CompileTaskWrapper :: hasSource );
6571 }
6672
6773 public Sync createMergeClassesTask () {
@@ -84,12 +90,112 @@ public FileCollection getMergeAdjustedClasspath(FileCollection classpath) {
8490 }
8591
8692 Set <File > files = new HashSet <>(classpath .getFiles ());
87- allCompileTaskStream ().map (AbstractCompile ::getDestinationDir ).forEach (files ::remove );
93+ allCompileTaskStream ().map (CompileTaskWrapper ::getDestinationDir ).forEach (files ::remove );
8894 files .add (helper ().getMergedDir ());
8995 return project .files (files .toArray ());
9096 }
9197
98+ private CompileTaskWrapper toWrapper (Task task ) {
99+ return task instanceof AbstractCompile
100+ ? new GradleTaskWrapper ((AbstractCompile ) task )
101+ : new ReflectionTaskWrapper (task );
102+ }
103+
92104 private JavaProjectHelper helper () {
93105 return new JavaProjectHelper (project );
94106 }
107+
108+ public interface CompileTaskWrapper {
109+ Task getTask ();
110+
111+ File getDestinationDir ();
112+
113+ boolean hasSource ();
114+ }
115+
116+ private static final class GradleTaskWrapper implements CompileTaskWrapper {
117+
118+ private final AbstractCompile task ;
119+
120+ GradleTaskWrapper (AbstractCompile task ) {
121+ this .task = task ;
122+ }
123+
124+ @ Override
125+ public Task getTask () {
126+ return task ;
127+ }
128+
129+ @ Override
130+ public File getDestinationDir () {
131+ return task .getDestinationDir ();
132+ }
133+
134+ @ Override
135+ public boolean hasSource () {
136+ return !task .getSource ().isEmpty ();
137+ }
138+ }
139+
140+ private static final class ReflectionTaskWrapper implements CompileTaskWrapper {
141+
142+ private final Task task ;
143+ private final Supplier <DirectoryProperty > destinationDir ;
144+ private final Supplier <FileCollection > source ;
145+
146+ ReflectionTaskWrapper (Task task ) {
147+ this .task = task ;
148+ this .destinationDir = supplier (
149+ task ,
150+ "getDestinationDirectory" ,
151+ DirectoryProperty .class
152+ );
153+ this .source = supplier (
154+ task ,
155+ "getSources" ,
156+ FileCollection .class
157+ );
158+ }
159+
160+ @ Override
161+ public Task getTask () {
162+ return task ;
163+ }
164+
165+ @ Override
166+ public File getDestinationDir () {
167+ return destinationDir .get ().getAsFile ().getOrNull ();
168+ }
169+
170+ @ Override
171+ public boolean hasSource () {
172+ return !source .get ().isEmpty ();
173+ }
174+
175+ private static <T > Supplier <T > supplier (Task task , String getterName , Class <T > getterReturnType ) {
176+ final Method m = getMethod (task , getterName );
177+
178+ return () -> {
179+ try {
180+ final Object result = m .invoke (task );
181+ return getterReturnType .cast (result );
182+ } catch (InvocationTargetException e ) {
183+ if (e .getTargetException () instanceof RuntimeException ) {
184+ throw (RuntimeException ) e .getTargetException ();
185+ }
186+ throw new RuntimeException (e .getTargetException ());
187+ } catch (IllegalAccessException e ) {
188+ throw new RuntimeException ("Failed to invoke " + getterName + " on " + task .getClass (), e );
189+ }
190+ };
191+ }
192+
193+ private static Method getMethod (Task task , String name ) {
194+ try {
195+ return task .getClass ().getMethod (name );
196+ } catch (NoSuchMethodException e ) {
197+ throw new IllegalStateException ("Method " + name + " missing on " + task .getClass (), e );
198+ }
199+ }
200+ }
95201}
0 commit comments