001package ball.lang.reflect; 002/*- 003 * ########################################################################## 004 * Utilities 005 * %% 006 * Copyright (C) 2020 - 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 java.lang.reflect.Constructor; 022import java.lang.reflect.Field; 023import java.lang.reflect.Member; 024import java.lang.reflect.Method; 025import java.lang.reflect.Parameter; 026import java.lang.reflect.ParameterizedType; 027import java.lang.reflect.Type; 028import java.util.EnumSet; 029import java.util.stream.Stream; 030import javax.lang.model.element.Modifier; 031 032import static java.util.stream.Collectors.joining; 033 034/** 035 * {@link java.lang.reflect} and {@link javax.lang.model.element} utility 036 * methods. 037 * 038 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 039 */ 040public interface JavaLangReflectMethods { 041 042 /** 043 * Method to translate {@link Class} and {@link Member} 044 * {@link java.lang.reflect.Modifier} flags to an {@link EnumSet} of 045 * {@link Modifier}s. 046 * 047 * @param modifiers The {@code int} representing the modifiers. 048 * 049 * @return The {@link EnumSet} of {@link Modifier}s. 050 */ 051 default EnumSet<Modifier> asModifierSet(int modifiers) { 052 EnumSet<Modifier> set = EnumSet.noneOf(Modifier.class); 053 054 Stream.of(java.lang.reflect.Modifier.toString(modifiers).split("[\\p{Space}]+")) 055 .filter(t -> (! t.isEmpty())) 056 .map(String::toUpperCase) 057 .map(Modifier::valueOf) 058 .forEach(set::add); 059 060 return set; 061 } 062 063 /** 064 * See {@link #asModifierSet(int)}. 065 * 066 * @param type The {@link Class}. 067 * 068 * @return The {@link EnumSet} of {@link Modifier}s. 069 */ 070 default EnumSet<Modifier> getModifiers(Class<?> type) { 071 return asModifierSet(type.getModifiers()); 072 } 073 074 /** 075 * See {@link #asModifierSet(int)}. 076 * 077 * @param member The {@link Member}. 078 * 079 * @return The {@link EnumSet} of {@link Modifier}s. 080 */ 081 default EnumSet<Modifier> getModifiers(Member member) { 082 return asModifierSet(member.getModifiers()); 083 } 084 085 /** 086 * Dispatches call to {@link #declaration(Constructor)}, 087 * {@link #declaration(Field)}, or {@link #declaration(Method)} as 088 * appropriate. 089 * 090 * @param member The target {@link Member}. 091 * 092 * @return {@link String} 093 */ 094 default String declaration(Member member) { 095 String string = null; 096 097 if (member instanceof Constructor) { 098 string = declaration((Constructor) member); 099 } else if (member instanceof Field) { 100 string = declaration((Field) member); 101 } else if (member instanceof Method) { 102 string = declaration((Method) member); 103 } else { 104 throw new IllegalArgumentException(String.valueOf(member)); 105 } 106 107 return string; 108 } 109 110 /** 111 * Method to generate a {@link Constructor} declaration. 112 * 113 * @param constructor The target {@link Constructor}. 114 * 115 * @return {@link String} 116 */ 117 default String declaration(Constructor<?> constructor) { 118 String string = 119 modifiers(constructor.getModifiers()) 120 + " " + constructor.getName() 121 + parameters(constructor.getParameters()) 122 + " " + exceptions(constructor.getGenericExceptionTypes()); 123 124 return string.trim(); 125 } 126 127 /** 128 * Method to generate a {@link Field} declaration. 129 * 130 * @param field The target {@link Field}. 131 * 132 * @return {@link String} 133 */ 134 default String declaration(Field field) { 135 String string = modifiers(field.getModifiers()) + " " + type(field.getGenericType()) + " " + field.getName(); 136 137 return string.trim(); 138 } 139 140 /** 141 * Method to generate a {@link Method} declaration. 142 * 143 * @param method The target {@link Method}. 144 * 145 * @return {@link String} 146 */ 147 default String declaration(Method method) { 148 return declaration(method.getModifiers(), method); 149 } 150 151 /** 152 * Method to generate a {@link Method} declaration. 153 * 154 * @param modifiers The adjusted modifiers. 155 * @param method The target {@link Method}. 156 * 157 * @return {@link String} 158 */ 159 default String declaration(int modifiers, Method method) { 160 return declaration(modifiers, method.getGenericReturnType(), method); 161 } 162 163 /** 164 * Method to generate a {@link Method} declaration. 165 * 166 * @param modifiers The adjusted modifiers. 167 * @param returnType The adjusted return {@link Type}. 168 * @param method The target {@link Method}. 169 * 170 * @return {@link String} 171 */ 172 default String declaration(int modifiers, Type returnType, Method method) { 173 return declaration(modifiers, type(returnType), method); 174 } 175 176 /** 177 * Method to generate a {@link Method} declaration. 178 * 179 * @param modifiers The adjusted modifiers. 180 * @param returnType The adjusted return {@link Type} 181 * (as a {@link String}). 182 * @param method The target {@link Method}. 183 * 184 * @return {@link String} 185 */ 186 default String declaration(int modifiers, String returnType, Method method) { 187 String string = 188 modifiers(modifiers) 189 + " " + returnType 190 + " " + method.getName() 191 + parameters(method.getParameters()) 192 + " " + exceptions(method.getGenericExceptionTypes()); 193 194 return string.trim(); 195 } 196 197 /** 198 * Method to generate a {@link Constructor} or {@link Method} parameter 199 * declaration. 200 * 201 * @param parameters The target {@link Parameter} array. 202 * 203 * @return {@link String} 204 */ 205 default String parameters(Parameter[] parameters) { 206 return Stream.of(parameters) 207 .map(t -> declaration(t)) 208 .collect(joining(", ", "(", ")")); 209 } 210 211 /** 212 * Method to generate a {@link Constructor} or {@link Method} thrown 213 * exception list. 214 * 215 * @param exceptions The target {@link Type} array. 216 * 217 * @return {@link String} 218 */ 219 default String exceptions(Type[] exceptions) { 220 String string = ""; 221 222 if (exceptions != null && exceptions.length > 0) { 223 string = 224 Stream.of(exceptions) 225 .map(t -> type(t)) 226 .collect(joining(", ", "throws ", "")); 227 } 228 229 return string; 230 } 231 232 /** 233 * Method to generate a {@link Parameter} declaration. 234 * 235 * @param parameter The target {@link Parameter}. 236 * 237 * @return {@link String} 238 */ 239 default String declaration(Parameter parameter) { 240 String string = 241 modifiers(parameter.getModifiers()) 242 + " " + type(parameter.getParameterizedType()) 243 + " " + parameter.getName(); 244 245 return string.trim(); 246 } 247 248 /** 249 * Method to generate modifiers for {@code declaration()} methods. 250 * 251 * @param modifiers See {@link Modifier}. 252 * 253 * @return {@link String} 254 */ 255 default String modifiers(int modifiers) { 256 return java.lang.reflect.Modifier.toString(modifiers); 257 } 258 259 /** 260 * Method to generate types for {@code declaration()} methods. 261 * 262 * @param type The {@link Type}. 263 * 264 * @return {@link String} 265 */ 266 default String type(Type type) { 267 String string = null; 268 269 if (type instanceof ParameterizedType) { 270 string = type((ParameterizedType) type); 271 } else if (type instanceof Class<?>) { 272 string = ((Class<?>) type).getSimpleName(); 273 } else { 274 string = type.getTypeName(); 275 } 276 277 return string; 278 } 279 280 /** 281 * Method to generate types for {@code declaration()} methods. 282 * 283 * @param type The {@link ParameterizedType}. 284 * 285 * @return {@link String} 286 */ 287 default String type(ParameterizedType type) { 288 return Stream.of(type.getActualTypeArguments()) 289 .map(t -> type(t)) 290 .collect(joining(",", type(type.getRawType()) + "<", ">")); 291 } 292}