Annotation specifying config store mode for enum classes #PL-2123 fixed

This commit is contained in:
Dmitry Kozlov 2013-09-20 12:19:23 +00:00
parent 97128384eb
commit fe9ae1963c
5 changed files with 112 additions and 26 deletions

View File

@ -25,7 +25,9 @@ import com.haulmont.cuba.core.config.type.TypeStringify;
import org.apache.commons.lang.ClassUtils;
import org.apache.commons.lang.StringUtils;
import javax.annotation.Nullable;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -279,17 +281,28 @@ public class ConfigUtil
if (defaultValue != null) {
return defaultValue.value();
} else {
TypeStringify stringConverter = TypeStringify.getInstance(configInterface, method);
Class<?> type = method.getReturnType();
String name = "Default" + StringUtils.capitalize(ClassUtils.getShortClassName(type));
for (Annotation annotation : method.getAnnotations()) {
Class annotationType = annotation.annotationType();
if (name.equals(ClassUtils.getShortClassName(annotationType))) {
Method valueMethod = annotationType.getMethod("value");
Object value = valueMethod.invoke(annotation);
TypeStringify stringifier = TypeStringify.getInstance(configInterface, method);
return stringifier.stringify(value);
if (EnumClass.class.isAssignableFrom(type)) {
@SuppressWarnings("unchecked")
Class<EnumClass> enumeration = (Class<EnumClass>) type;
EnumStore mode = getAnnotation(configInterface, method, EnumStore.class, true);
if (EnumStoreMode.ID == mode.value()) {
Class<?> idType = getEnumIdType(enumeration);
String name = "Default" + StringUtils.capitalize(ClassUtils.getShortClassName(idType));
Object value = getAnnotationValue(method, name);
if (value != null) {
Method fromId = enumeration.getDeclaredMethod("fromId", idType);
return stringConverter.stringify(fromId.invoke(null, value));
}
return NO_DEFAULT;
}
}
String name = "Default" + StringUtils.capitalize(ClassUtils.getShortClassName(type));
Object value = getAnnotationValue(method, name);
if (value != null) {
return stringConverter.stringify(value);
}
}
return NO_DEFAULT;
} catch (Exception ex) {
@ -297,6 +310,18 @@ public class ConfigUtil
}
}
@Nullable
private static Object getAnnotationValue(AnnotatedElement annotated, String name) throws ReflectiveOperationException {
for (Annotation annotation : annotated.getAnnotations()) {
Class annotationType = annotation.annotationType();
if (name.equals(ClassUtils.getShortClassName(annotationType))) {
Method method = annotationType.getMethod("value");
return method.invoke(annotation);
}
}
return null;
}
public static SourceType getSourceType(Class<?> configInterface, Method method) {
Source source = method.getAnnotation(Source.class);
if (source == null) {

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2008-2013 Haulmont. All rights reserved.
* Use is subject to license terms, see http://www.cuba-platform.com/license for details.
*/
package com.haulmont.cuba.core.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation for config properties, specifying the way to store enum values.
* @see EnumStoreMode
* @author kozlov
* @version $Id$
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface EnumStore {
public EnumStoreMode value();
}

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2008-2013 Haulmont. All rights reserved.
* Use is subject to license terms, see http://www.cuba-platform.com/license for details.
*/
package com.haulmont.cuba.core.config;
/**
* Identifies the way to store enum class values in the config storage.
* @author kozlov
* @version $Id$
*/
public enum EnumStoreMode {
/**
* Store enum IDs.
* Requires public static {@code fromId} class and work only with primitive ids
* for which stringify and type factory instances can be inferred from class definitions.
*/
ID,
/**
* Store enum names.
*/
NAME
}

View File

@ -20,6 +20,8 @@ package com.haulmont.cuba.core.config.type;
import com.haulmont.chile.core.datatypes.impl.EnumClass;
import com.haulmont.cuba.core.config.ConfigUtil;
import com.haulmont.cuba.core.config.EnumStore;
import com.haulmont.cuba.core.config.EnumStoreMode;
import com.haulmont.cuba.core.config.SourceType;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.AppBeans;
@ -94,21 +96,25 @@ public abstract class TypeFactory
} else {
if (Entity.class.isAssignableFrom(returnType)) {
return AppBeans.get(ENTITY_FACTORY_BEAN_NAME, TypeFactory.class);
} else if (EnumClass.class.isAssignableFrom(returnType)) {
@SuppressWarnings("unchecked")
Class<EnumClass> enumeration = (Class<EnumClass>) returnType;
Class<?> idType = ConfigUtil.getEnumIdType(enumeration);
TypeFactory idFactory = getInferred(idType);
try {
Method fromIdMethod = returnType.getMethod("fromId", idType);
if (!isAcceptableMethod(returnType, fromIdMethod) || idFactory == null) {
throw new IllegalArgumentException("Cannot use method as factory method: " + method);
}
return new EnumClassFactory(idFactory, fromIdMethod);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("fromId method is not found for " + enumeration.getName());
}
} else {
if (EnumClass.class.isAssignableFrom(returnType)) {
EnumStore mode = ConfigUtil.getAnnotation(configInterface, method, EnumStore.class, true);
if (mode != null && EnumStoreMode.ID == mode.value()) {
@SuppressWarnings("unchecked")
Class<EnumClass> enumeration = (Class<EnumClass>) returnType;
Class<?> idType = ConfigUtil.getEnumIdType(enumeration);
TypeFactory idFactory = getInferred(idType);
try {
Method fromIdMethod = returnType.getMethod("fromId", idType);
if (!isAcceptableMethod(returnType, fromIdMethod) || idFactory == null) {
throw new IllegalArgumentException("Cannot use method as factory method: " + method);
}
return new EnumClassFactory(idFactory, fromIdMethod);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("fromId method is not found for " + enumeration.getName());
}
}
}
TypeFactory factoryT = getInferred(returnType);
if (factoryT == null) {
throw new IllegalArgumentException("Unsupported return type for " + method);

View File

@ -20,6 +20,8 @@ package com.haulmont.cuba.core.config.type;
import com.haulmont.chile.core.datatypes.impl.EnumClass;
import com.haulmont.cuba.core.config.ConfigUtil;
import com.haulmont.cuba.core.config.EnumStore;
import com.haulmont.cuba.core.config.EnumStoreMode;
import com.haulmont.cuba.core.entity.Entity;
import java.lang.reflect.Method;
@ -68,10 +70,13 @@ public abstract class TypeStringify
return new EntityStringify();
}
if (EnumClass.class.isAssignableFrom(methodType)) {
@SuppressWarnings("unchecked")
Class<EnumClass> enumeration = (Class<EnumClass>) methodType;
TypeStringify idStringify = getInferred(ConfigUtil.getEnumIdType(enumeration));
return new EnumClassStringify(idStringify);
EnumStore mode = ConfigUtil.getAnnotation(configInterface, method, EnumStore.class, true);
if (mode != null && EnumStoreMode.ID == mode.value()) {
@SuppressWarnings("unchecked")
Class<EnumClass> enumeration = (Class<EnumClass>) methodType;
TypeStringify idStringify = getInferred(ConfigUtil.getEnumIdType(enumeration));
return new EnumClassStringify(idStringify);
}
}
return getInferred(methodType);
}