001package ball.util.ant.taskdefs; 002/*- 003 * ########################################################################## 004 * Utilities 005 * $Id: ProcessClassesTask.html 5431 2020-02-12 19:03:17Z ball $ 006 * $HeadURL: svn+ssh://svn.hcf.dev/var/spool/scm/repository.svn/hcf-dev/blog/2019-07-08-fivethirtyeight-best-scrabble-string/src/main/resources/javadoc/src-html/ball/util/ant/taskdefs/ProcessClassesTask.html $ 007 * %% 008 * Copyright (C) 2008 - 2020 Allen D. Ball 009 * %% 010 * Licensed under the Apache License, Version 2.0 (the "License"); 011 * you may not use this file except in compliance with the License. 012 * You may obtain a copy of the License at 013 * 014 * http://www.apache.org/licenses/LICENSE-2.0 015 * 016 * Unless required by applicable law or agreed to in writing, software 017 * distributed under the License is distributed on an "AS IS" BASIS, 018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 019 * See the License for the specific language governing permissions and 020 * limitations under the License. 021 * ########################################################################## 022 */ 023import ball.annotation.processing.ClassFileProcessor; 024import java.io.File; 025import java.util.Set; 026import java.util.TreeSet; 027import java.util.stream.Stream; 028import lombok.Getter; 029import lombok.NoArgsConstructor; 030import lombok.Setter; 031import lombok.ToString; 032import lombok.experimental.Accessors; 033import org.apache.tools.ant.BuildException; 034import org.apache.tools.ant.Task; 035import org.apache.tools.ant.taskdefs.optional.depend.ClassFile; 036import org.apache.tools.ant.taskdefs.optional.depend.ClassFileUtils; 037import org.apache.tools.ant.taskdefs.optional.depend.DirectoryIterator; 038import org.apache.tools.ant.types.Path; 039import org.apache.tools.ant.util.ClasspathUtils; 040 041import static java.lang.reflect.Modifier.isAbstract; 042import static java.util.Comparator.comparing; 043 044/** 045 * {@link.uri http://ant.apache.org/ Ant} {@link Task} to bootstrap 046 * {@link javax.annotation.processing.Processor}s. Creates and invokes 047 * {@link ClassFileProcessor}s found on the class path. 048 * 049 * {@ant.task} 050 * 051 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 052 * @version $Revision: 5431 $ 053 */ 054@NoArgsConstructor @ToString 055public class ProcessClassesTask extends Task 056 implements AnnotatedAntTask, 057 ClasspathDelegateAntTask { 058 @Getter @Setter @Accessors(chain = true, fluent = true) 059 private ClasspathUtils.Delegate delegate = null; 060 @Getter @Setter 061 private File basedir = null; 062 @Getter 063 private Path srcPath = null; 064 @Getter @Setter 065 private File destdir = null; 066 067 public void setSrcdir(Path srcdir) { 068 if (srcPath == null) { 069 srcPath = srcdir; 070 } else { 071 srcPath.append(srcdir); 072 } 073 } 074 075 public Path createSrc() { 076 if (srcPath == null) { 077 srcPath = new Path(getProject()); 078 } 079 080 return srcPath.createPath(); 081 } 082 083 @Override 084 public void init() throws BuildException { 085 super.init(); 086 ClasspathDelegateAntTask.super.init(); 087 } 088 089 @Override 090 public void execute() throws BuildException { 091 super.execute(); 092 AnnotatedAntTask.super.execute(); 093 094 try { 095 if (getBasedir() == null) { 096 setBasedir(getProject().resolveFile(".")); 097 } 098 099 if (getDestdir() == null) { 100 setDestdir(getBasedir()); 101 } 102 103 for (Class<?> type : getClassSet()) { 104 if (ClassFileProcessor.class.isAssignableFrom(type)) { 105 if (! isAbstract(type.getModifiers())) { 106 type.asSubclass(ClassFileProcessor.class).newInstance() 107 .process(getClassSet(), getDestdir()); 108 } 109 } 110 } 111 } catch (BuildException exception) { 112 throw exception; 113 } catch (RuntimeException exception) { 114 throw exception; 115 } catch (Throwable throwable) { 116 throwable.printStackTrace(); 117 throw new BuildException(throwable); 118 } 119 } 120 121 protected Set<Class<?>> getClassSet() throws BuildException { 122 TreeSet<Class<?>> set = new TreeSet<>(comparing(Class::getName)); 123 124 try { 125 for (ClassFile file : new DirectoryIterator(getBasedir(), true)) { 126 set.add(getClassForName(file.getFullClassName())); 127 } 128 } catch (BuildException exception) { 129 throw exception; 130 } catch (RuntimeException exception) { 131 throw exception; 132 } catch (Exception exception) { 133 throw new BuildException(exception); 134 } 135 136 return set; 137 } 138 139 protected File getJavaFile(Class<?> type) { 140 File file = null; 141 142 if (srcPath != null && type != null) { 143 while (type.getDeclaringClass() != null) { 144 type = type.getDeclaringClass(); 145 } 146 147 while (type.getEnclosingClass() != null) { 148 type = type.getEnclosingClass(); 149 } 150 151 String path = 152 ClassFileUtils.convertDotName(type.getCanonicalName()); 153 154 file = 155 Stream.of(srcPath.list()) 156 .map(t -> new File(t, path + ".java")) 157 .filter(File::isFile) 158 .findFirst().orElse(null); 159 } 160 161 return file; 162 } 163}