/*
*
* * Copyright (c) 2016. David Sowerby
* *
* * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* * the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* * specific language governing permissions and limitations under the License.
*
*/
package uk.q3c.krail.core.option;
import org.reflections.ReflectionUtils;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.q3c.krail.core.i18n.I18NKey;
import javax.annotation.Nonnull;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* A utility class to find {@link OptionKey} instances by reflection
* <p>
* Created by David Sowerby on 07/08/15.
*/
public class OptionKeyLocator {
private static Logger log = LoggerFactory.getLogger(OptionKeyLocator.class);
/**
* Scans the entire application by reflection for instance of {@link OptionKey} and returns a Set of data types they use. Only works with static fields,
* as {@link OptionContext} implementations are not instantiated (but there is no reason not to use static fields for Option keys
*
* @return Set of data types used by {@link OptionKey}
*/
public Set<Class<?>> contextKeyTypes() {
Reflections reflections = new Reflections();
Set<Class<? extends OptionContext>> contexts = reflections.getSubTypesOf(OptionContext.class);
Set<Class<?>> keyTypes = new HashSet<>();
for (Class<? extends OptionContext> contextClass : contexts) {
Set<Field> contextFields = ReflectionUtils.getAllFields(contextClass, p -> p.getType()
.equals(OptionKey.class));
for (Field contextField : contextFields) {
try {
contextField.setAccessible(true);
final OptionKey key = (OptionKey) contextField.get(null);
Object defaultValue = key.getDefaultValue();
if (defaultValue instanceof I18NKey) {
keyTypes.add(I18NKey.class);
} else if (defaultValue.getClass()
.isEnum()) {
keyTypes.add(Enum.class);
} else {
keyTypes.add(defaultValue.getClass());
}
} catch (IllegalAccessException | NullPointerException e) {
log.warn("unable to read field {}", contextField.getName());
}
}
}
return keyTypes;
}
/**
* {@inheritDoc}
*/
@Nonnull
public Map<OptionKey, Class<?>> contextKeyMap(OptionContext context) {
Set<Field> contextFields = ReflectionUtils.getAllFields(context.getClass(), p -> p.getType()
.equals(OptionKey.class));
Map<OptionKey, Class<?>> keys = new HashMap<>();
for (java.lang.reflect.Field field : contextFields) {
field.setAccessible(true);
try {
OptionKey key = (OptionKey) field.get(context);
if (key != null) {
keys.put(key, field.getType());
}
} catch (IllegalAccessException e) {
log.error("Unable to access field {}", field.getName());
}
}
return keys;
}
}