001package ball.util.ant.taskdefs; 002/*- 003 * ########################################################################## 004 * Utilities 005 * $Id: TypeTask.BeanInfoFor.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/TypeTask.BeanInfoFor.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.beans.PropertyDescriptorsTableModel; 024import ball.swing.table.SimpleTableModel; 025import java.beans.BeanDescriptor; 026import java.beans.BeanInfo; 027import java.beans.Introspector; 028import java.beans.PropertyDescriptor; 029import java.lang.reflect.Constructor; 030import java.lang.reflect.Field; 031import java.lang.reflect.Method; 032import java.lang.reflect.TypeVariable; 033import java.net.URL; 034import java.util.ArrayList; 035import lombok.Getter; 036import lombok.NoArgsConstructor; 037import lombok.Setter; 038import lombok.ToString; 039import lombok.experimental.Accessors; 040import org.apache.commons.lang3.ClassUtils; 041import org.apache.tools.ant.BuildException; 042import org.apache.tools.ant.Task; 043import org.apache.tools.ant.util.ClasspathUtils; 044 045import static ball.lang.Punctuation.GT; 046import static ball.lang.Punctuation.LT; 047import static lombok.AccessLevel.PROTECTED; 048import static org.apache.commons.lang3.StringUtils.EMPTY; 049 050/** 051 * Abstract {@link.uri http://ant.apache.org/ Ant} {@link Task} to specify a 052 * type ({@link Class}). 053 * 054 * {@ant.task} 055 * 056 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 057 * @version $Revision: 5431 $ 058 */ 059@NoArgsConstructor(access = PROTECTED) 060public abstract class TypeTask extends Task 061 implements AnnotatedAntTask, 062 ClasspathDelegateAntTask { 063 @Getter @Setter @Accessors(chain = true, fluent = true) 064 private ClasspathUtils.Delegate delegate = null; 065 @NotNull @Getter 066 private String type = null; 067 068 public void setType(String string) { 069 type = string; 070 ClasspathDelegateAntTask.super.setClassname(type); 071 } 072 073 @Override 074 public void setClassname(String string) { setType(string); } 075 076 @Override 077 public void init() throws BuildException { 078 super.init(); 079 ClasspathDelegateAntTask.super.init(); 080 } 081 082 @Override 083 public void execute() throws BuildException { 084 super.execute(); 085 AnnotatedAntTask.super.execute(); 086 } 087 088 /** 089 * {@link.uri http://ant.apache.org/ Ant} 090 * {@link org.apache.tools.ant.Task} to display {@link BeanInfo} 091 * for a specified {@link Class}. 092 * 093 * {@ant.task} 094 */ 095 @AntTask("bean-info-for") 096 @NoArgsConstructor @ToString 097 public static class BeanInfoFor extends TypeTask { 098 @Override 099 public void execute() throws BuildException { 100 super.execute(); 101 102 try { 103 log(Introspector.getBeanInfo(getClassForName(getType()))); 104 } catch (BuildException exception) { 105 throw exception; 106 } catch (Throwable throwable) { 107 throwable.printStackTrace(); 108 throw new BuildException(throwable); 109 } 110 } 111 112 private void log(BeanInfo bean) { 113 log(new BeanHeaderTableModel(bean.getBeanDescriptor())); 114 log(); 115 log(new TableModelImpl(bean.getPropertyDescriptors())); 116 log(bean.getAdditionalBeanInfo()); 117 } 118 119 private void log(BeanInfo[] beans) { 120 if (beans != null) { 121 for (BeanInfo bean : beans) { 122 log(); 123 log(bean); 124 } 125 } 126 } 127 128 private class BeanHeaderTableModel extends SimpleTableModel { 129 private static final long serialVersionUID = 2338583773511453873L; 130 131 public BeanHeaderTableModel(BeanDescriptor descriptor) { 132 super(new Object[][] { }, 2); 133 134 row("Bean Class:", 135 descriptor.getBeanClass().getName()); 136 137 if (descriptor.getCustomizerClass() != null) { 138 row("Customizer Class:", 139 descriptor.getCustomizerClass().getName()); 140 } 141 } 142 } 143 144 private class TableModelImpl extends PropertyDescriptorsTableModel { 145 private static final long serialVersionUID = -5817972183666452609L; 146 147 public TableModelImpl(PropertyDescriptor[] rows) { super(rows); } 148 149 @Override 150 public Object getValueAt(int y, int x) { 151 Object value = super.getValueAt(y, x); 152 153 if (value instanceof Class<?>) { 154 value = ((Class<?>) value).getCanonicalName(); 155 } 156 157 return value; 158 } 159 } 160 } 161 162 /** 163 * {@link.uri http://ant.apache.org/ Ant} 164 * {@link org.apache.tools.ant.Task} to display superclasses of a 165 * specified {@link Class}. 166 * 167 * {@ant.task} 168 */ 169 @AntTask("is-assignable-from") 170 @NoArgsConstructor @ToString 171 public static class IsAssignableFrom extends TypeTask { 172 @NotNull @Getter @Setter 173 private String subtype = null; 174 175 @Override 176 public void execute() throws BuildException { 177 super.execute(); 178 179 try { 180 Class<?> supertype = getClassForName(getType()); 181 Class<?> subtype = getClassForName(getSubtype()); 182 183 log(supertype.getName() + " is " 184 + (supertype.isAssignableFrom(subtype) ? EMPTY : "not ") 185 + "assignable from " + subtype.getName()); 186 } catch (BuildException exception) { 187 throw exception; 188 } catch (Throwable throwable) { 189 throwable.printStackTrace(); 190 throw new BuildException(throwable); 191 } 192 } 193 } 194 195 /** 196 * {@link.uri http://ant.apache.org/ Ant} 197 * {@link org.apache.tools.ant.Task} to display members of a specified 198 * {@link Class}. 199 * 200 * {@ant.task} 201 */ 202 @AntTask("members-of") 203 @NoArgsConstructor @ToString 204 public static class MembersOf extends TypeTask { 205 @Override 206 public void execute() throws BuildException { 207 super.execute(); 208 209 try { 210 Class<?> type = getClassForName(getType()); 211 212 log(String.valueOf(type)); 213 214 for (Constructor<?> constructor : 215 type.getDeclaredConstructors()) { 216 log(constructor.toGenericString()); 217 } 218 219 for (Field field : type.getDeclaredFields()) { 220 log(field.toGenericString()); 221 } 222 223 for (Method method : type.getDeclaredMethods()) { 224 log(method.toGenericString()); 225 } 226 227 for (Class<?> cls : type.getDeclaredClasses()) { 228 log(cls.toString()); 229 } 230 } catch (BuildException exception) { 231 throw exception; 232 } catch (Throwable throwable) { 233 throwable.printStackTrace(); 234 throw new BuildException(throwable); 235 } 236 } 237 } 238 239 /** 240 * {@link.uri http://ant.apache.org/ Ant} 241 * {@link org.apache.tools.ant.Task} to display resource path to a 242 * specified {@link Class}. 243 * 244 * {@ant.task} 245 */ 246 @AntTask("resource-path-to") 247 @NoArgsConstructor @ToString 248 public static class ResourcePathTo extends TypeTask { 249 @Override 250 public void execute() throws BuildException { 251 super.execute(); 252 253 try { 254 Class<?> type = getClassForName(getType()); 255 256 log(String.valueOf(type)); 257 258 URL url = 259 type.getClass() 260 .getResource(type.getSimpleName() + ".class"); 261 262 log(String.valueOf(url)); 263 } catch (BuildException exception) { 264 throw exception; 265 } catch (Throwable throwable) { 266 throwable.printStackTrace(); 267 throw new BuildException(throwable); 268 } 269 } 270 } 271 272 /** 273 * {@link.uri http://ant.apache.org/ Ant} 274 * {@link org.apache.tools.ant.Task} to display superclasses of a 275 * specified {@link Class}. 276 * 277 * {@ant.task} 278 */ 279 @AntTask("superclasses-of") 280 @NoArgsConstructor @ToString 281 public static class SuperclassesOf extends TypeTask { 282 @Override 283 public void execute() throws BuildException { 284 super.execute(); 285 286 try { 287 ArrayList<Class<?>> list = new ArrayList<>(); 288 Class<?> type = getClassForName(getType()); 289 290 list.add(type); 291 list.addAll(ClassUtils.getAllSuperclasses(type)); 292 list.addAll(ClassUtils.getAllInterfaces(type)); 293 294 for (Class<?> superclass : list) { 295 log(toString(superclass)); 296 } 297 } catch (BuildException exception) { 298 throw exception; 299 } catch (Throwable throwable) { 300 throwable.printStackTrace(); 301 throw new BuildException(throwable); 302 } 303 } 304 305 private String toString(Class<?> type) { 306 StringBuilder buffer = new StringBuilder(type.getName()); 307 308 if (type.getTypeParameters().length > 0) { 309 buffer.append(LT.lexeme()); 310 311 for (TypeVariable<?> parameter : type.getTypeParameters()) { 312 buffer.append(parameter); 313 } 314 315 buffer.append(GT.lexeme()); 316 } 317 318 return buffer.toString(); 319 } 320 } 321}