4.5 KiB
+++ title = "reflectie" draft = false tags = [ "code", "java", "reflectie" ] date = "2013-03-12" +++
Reflectie, Classpath scanning etc
Oplijsten van fields die enkel boolean en true zijn
public static String listTrueBooleanFields(Object object) {
List<String> parts = Lists.newArrayList();
try {
for (Field field : object.getClass().getDeclaredFields()) {
boolean accessibleFlag = field.isAccessible();
field.setAccessible(true);
if (isTrueBooleanField(object, field)) {
parts.add(makeCamelCaseNatural(field.getName()));
}
field.setAccessible(accessibleFlag);
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
return StringUtils.join(parts, ", ");
}
private static boolean isTrueBooleanField(Object object, Field field) throws IllegalAccessException {
return isBoolean(field) && (Boolean) field.get(object);
}
private static boolean isBoolean(Field field) {
return Boolean.class.isAssignableFrom(field.getType()) || boolean.class.isAssignableFrom(field.getType());
}
Nieuwe instantie van een klasse met default constructor
public class ReflectionUtils {
public static <T> T createNewInstanceOf(Class<T> classToCreate) {
try {
Constructor<T> noArgConstructor = classToCreate.getDeclaredConstructor();
boolean accessibleFlag = noArgConstructor.isAccessible();
noArgConstructor.setAccessible(true);
T newInstance = noArgConstructor.newInstance();
noArgConstructor.setAccessible(accessibleFlag);
return newInstance;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Class files vinden in bepaalde packages
Met Spring
Met hulp van spring classes zoals org.springframework.core.io.support.ResourcePatternResolver
en org.springframework.core.type.classreading.MetadataReaderFactory
:
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(basePackage) + "/" + this.resourcePattern;
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
for (int i = 0; i < resources.length; i++) {
Resource resource = resources[i];
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
Class<?> clazz = null;
try {
clazz = Class.forName(metadataReader.getClassMetadata().getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
candidates.add(clazz);
}
}
CLASSPATH_ALL_URL_PREFIX
is "classpath*:"
.
De isCandidateComponent
method accepteert of verwerpt een item afhankelijk van de metadata met hulp van de spring interface org.springframework.core.type.filter.TypeFilter
:
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return true;
}
}
Het is ook mogelijk om een "default" filter te voorzien die alles include: new RegexPatternTypeFilter(Pattern.compile(".*"));
.
Subtypes van een bepaalde klasse vinden
Kan ook met de bovenstaande code (de ClassPathScanningCandidateComponentProvider
dus):
public <T> Set<Class<?>> getSubTypesOf(Class<T> type) {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AssignableTypeFilter(type));
Set<Class<?>> candidateSubtypes = provider.findCandidateComponents(getPackageToScan());
candidateSubtypes.remove(type);
return candidateSubtypes;
}
get only concrete subclasses
In combinatie met bovenstaande method:
public <T> Set<Class<?>> getConcreteSubTypesOf(Class<T> type) {
Set<Class<?>> result = new HashSet<Class<?>>();
for (Class<?> aClass : getSubTypesOf(type)) {
if (isConcrete(aClass)) {
result.add(aClass);
}
}
return result;
}
private boolean isConcrete(Class<?> aClass) {
return !Modifier.isAbstract(aClass.getModifiers());
}
Zonder Spring
Gebruik http://code.google.com/p/reflections/ -
Reflections reflections = new Reflections("my.project.prefix");
Set<Class<? extends SomeClassOrInterface>> subTypes = reflections.getSubTypesOf(SomeClassOrInterface.class);
Alles zelf doen?
Slecht idee, enige optie is alle class files van het classpath als files behandelen, Class.forName
gebruiken om classes in te laden (slecht idee) en instanceof
ofzoiets gebruiken. Bytecode scanning gebeurt door de twee bovenstaanden, maar is niet triviaal zelf te doen.