001package ball.util.ant.taskdefs; 002/*- 003 * ########################################################################## 004 * Utilities 005 * %% 006 * Copyright (C) 2008 - 2022 Allen D. Ball 007 * %% 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 * ########################################################################## 020 */ 021import ball.beans.PropertyDescriptorsTableModel; 022import ball.lang.reflect.JavaLangReflectMethods; 023import ball.swing.table.SimpleTableModel; 024import java.beans.BeanDescriptor; 025import java.beans.BeanInfo; 026import java.beans.Introspector; 027import java.beans.PropertyDescriptor; 028import java.net.URL; 029import java.util.ArrayList; 030import java.util.stream.Stream; 031import lombok.Getter; 032import lombok.NoArgsConstructor; 033import lombok.Setter; 034import lombok.ToString; 035import lombok.experimental.Accessors; 036import org.apache.commons.lang3.ClassUtils; 037import org.apache.tools.ant.BuildException; 038import org.apache.tools.ant.Task; 039import org.apache.tools.ant.util.ClasspathUtils; 040 041import static lombok.AccessLevel.PROTECTED; 042import static org.apache.commons.lang3.StringUtils.EMPTY; 043 044/** 045 * Abstract {@link.uri http://ant.apache.org/ Ant} {@link Task} to specify a 046 * type ({@link Class}). 047 * 048 * {@ant.task} 049 * 050 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 051 */ 052@NoArgsConstructor(access = PROTECTED) 053public abstract class TypeTask extends Task implements AnnotatedAntTask, 054 ClasspathDelegateAntTask, JavaLangReflectMethods { 055 @Getter @Setter @Accessors(chain = true, fluent = true) 056 private ClasspathUtils.Delegate delegate = null; 057 @NotNull @Getter 058 private String type = null; 059 060 public void setType(String string) { 061 type = string; 062 ClasspathDelegateAntTask.super.setClassname(type); 063 } 064 065 @Override 066 public void setClassname(String string) { setType(string); } 067 068 @Override 069 public void init() throws BuildException { 070 super.init(); 071 ClasspathDelegateAntTask.super.init(); 072 } 073 074 @Override 075 public void execute() throws BuildException { 076 super.execute(); 077 AnnotatedAntTask.super.execute(); 078 } 079 080 /** 081 * {@link.uri http://ant.apache.org/ Ant} 082 * {@link org.apache.tools.ant.Task} to display {@link BeanInfo} 083 * for a specified {@link Class}. 084 * 085 * {@ant.task} 086 */ 087 @AntTask("bean-info-for") 088 @NoArgsConstructor @ToString 089 public static class BeanInfoFor extends TypeTask { 090 @Override 091 public void execute() throws BuildException { 092 super.execute(); 093 094 try { 095 log(Introspector.getBeanInfo(getClassForName(getType()))); 096 } catch (BuildException exception) { 097 throw exception; 098 } catch (Throwable throwable) { 099 throwable.printStackTrace(); 100 throw new BuildException(throwable); 101 } 102 } 103 104 private void log(BeanInfo bean) { 105 log(new BeanHeaderTableModel(bean.getBeanDescriptor())); 106 log(); 107 log(new TableModelImpl(bean.getPropertyDescriptors())); 108 log(bean.getAdditionalBeanInfo()); 109 } 110 111 private void log(BeanInfo[] beans) { 112 if (beans != null) { 113 for (BeanInfo bean : beans) { 114 log(); 115 log(bean); 116 } 117 } 118 } 119 120 @ToString 121 private class BeanHeaderTableModel extends SimpleTableModel { 122 private static final long serialVersionUID = -154550807608756372L; 123 124 public BeanHeaderTableModel(BeanDescriptor descriptor) { 125 super(new Object[][] { }, 2); 126 127 row("Bean Class:", descriptor.getBeanClass().getName()); 128 129 if (descriptor.getCustomizerClass() != null) { 130 row("Customizer Class:", descriptor.getCustomizerClass().getName()); 131 } 132 } 133 } 134 135 @ToString 136 private class TableModelImpl extends PropertyDescriptorsTableModel { 137 private static final long serialVersionUID = 3641199494457667293L; 138 139 public TableModelImpl(PropertyDescriptor[] rows) { super(rows); } 140 141 @Override 142 public Object getValueAt(int y, int x) { 143 Object value = super.getValueAt(y, x); 144 145 if (value instanceof Class<?>) { 146 value = ((Class<?>) value).getCanonicalName(); 147 } 148 149 return value; 150 } 151 } 152 } 153 154 /** 155 * {@link.uri http://ant.apache.org/ Ant} 156 * {@link org.apache.tools.ant.Task} to display superclasses of a 157 * specified {@link Class}. 158 * 159 * {@ant.task} 160 */ 161 @AntTask("is-assignable-from") 162 @NoArgsConstructor @ToString 163 public static class IsAssignableFrom extends TypeTask { 164 @NotNull @Getter @Setter 165 private String subtype = null; 166 167 @Override 168 public void execute() throws BuildException { 169 super.execute(); 170 171 try { 172 Class<?> supertype = getClassForName(getType()); 173 Class<?> subtype = getClassForName(getSubtype()); 174 175 log(supertype.getName() + " is " + (supertype.isAssignableFrom(subtype) ? EMPTY : "not ") 176 + "assignable from " + subtype.getName()); 177 } catch (BuildException exception) { 178 throw exception; 179 } catch (Throwable throwable) { 180 throwable.printStackTrace(); 181 throw new BuildException(throwable); 182 } 183 } 184 } 185 186 /** 187 * {@link.uri http://ant.apache.org/ Ant} 188 * {@link org.apache.tools.ant.Task} to display members of a specified 189 * {@link Class}. 190 * 191 * {@ant.task} 192 */ 193 @AntTask("members-of") 194 @NoArgsConstructor @ToString 195 public static class MembersOf extends TypeTask { 196 @Override 197 public void execute() throws BuildException { 198 super.execute(); 199 200 try { 201 Class<?> type = getClassForName(getType()); 202 203 log(type(type)); 204 Stream.of(type.getDeclaredClasses()) 205 .forEach(t -> log(type(t))); 206 Stream.of(type.getDeclaredFields()) 207 .forEach(t -> log(declaration(t))); 208 Stream.of(type.getDeclaredConstructors()) 209 .forEach(t -> log(declaration(t))); 210 Stream.of(type.getDeclaredMethods()) 211 .forEach(t -> log(declaration(t))); 212 } catch (BuildException exception) { 213 throw exception; 214 } catch (Throwable throwable) { 215 throwable.printStackTrace(); 216 throw new BuildException(throwable); 217 } 218 } 219 } 220 221 /** 222 * {@link.uri http://ant.apache.org/ Ant} 223 * {@link org.apache.tools.ant.Task} to display resource path to a 224 * specified {@link Class}. 225 * 226 * {@ant.task} 227 */ 228 @AntTask("resource-path-to") 229 @NoArgsConstructor @ToString 230 public static class ResourcePathTo extends TypeTask { 231 @Override 232 public void execute() throws BuildException { 233 super.execute(); 234 235 try { 236 Class<?> type = getClassForName(getType()); 237 238 log(String.valueOf(type)); 239 240 URL url = type.getClass().getResource(type.getSimpleName() + ".class"); 241 242 log(String.valueOf(url)); 243 } catch (BuildException exception) { 244 throw exception; 245 } catch (Throwable throwable) { 246 throwable.printStackTrace(); 247 throw new BuildException(throwable); 248 } 249 } 250 } 251 252 /** 253 * {@link.uri http://ant.apache.org/ Ant} 254 * {@link org.apache.tools.ant.Task} to display superclasses of a 255 * specified {@link Class}. 256 * 257 * {@ant.task} 258 */ 259 @AntTask("superclasses-of") 260 @NoArgsConstructor @ToString 261 public static class SuperclassesOf extends TypeTask { 262 @Override 263 public void execute() throws BuildException { 264 super.execute(); 265 266 try { 267 ArrayList<Class<?>> list = new ArrayList<>(); 268 Class<?> type = getClassForName(getType()); 269 270 list.add(type); 271 list.addAll(ClassUtils.getAllSuperclasses(type)); 272 list.addAll(ClassUtils.getAllInterfaces(type)); 273 274 for (Class<?> superclass : list) { 275 log(type(superclass)); 276 } 277 } catch (BuildException exception) { 278 throw exception; 279 } catch (Throwable throwable) { 280 throwable.printStackTrace(); 281 throw new BuildException(throwable); 282 } 283 } 284 } 285}