Skip to content

Commit

Permalink
feat(keyType): support specifying keyType in Assemble annotation, to …
Browse files Browse the repository at this point in the history
…convert the property value corresponding to key to the specified type before filling starts (GitHub #153) (#154)
  • Loading branch information
Createsequence authored Sep 17, 2023
1 parent 3ee3d8b commit 0a6cee5
Show file tree
Hide file tree
Showing 27 changed files with 250 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,22 @@
*/
String key() default "";

/**
* <p>The type to which the key value of target should be converted
* when fetching the data source from the data source.
*
* <p>For example, the data source obtained from the data source
* is grouped according to the key of the {@link Long} type,
* and the key value corresponding to the current operation is {@link Integer},
* then the {@code keyType} needs to be {@link Long} at this time.<br />
* When the actual operation is performed,
* the key value is automatically converted from Integer to {@link Long} type.
*
* @return key type
* @since 2.2.0
*/
Class<?> keyType() default Object.class;

/**
* The namespace of the data source container to be used.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,22 @@
*/
String key() default "";

/**
* <p>The type to which the key value of target should be converted
* when fetching the data source from the data source.
*
* <p>For example, the data source obtained from the data source
* is grouped according to the key of the {@link Long} type,
* and the key value corresponding to the current operation is {@link Integer},
* then the {@code keyType} needs to be {@link Long} at this time.<br />
* When the actual operation is performed,
* the key value is automatically converted from Integer to {@link Long} type.
*
* @return key type
* @since 2.2.0
*/
Class<?> keyType() default Object.class;

/**
* Sort values.
* The lower the value, the higher the priority.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@
*/
String key() default "";

/**
* <p>The type to which the key value of target should be converted
* when fetching the data source from the data source.
*
* <p>For example, the data source obtained from the data source
* is grouped according to the key of the {@link Long} type,
* and the key value corresponding to the current operation is {@link Integer},
* then the {@code keyType} needs to be {@link Long} at this time.<br />
* When the actual operation is performed,
* the key value is automatically converted from Integer to {@link Long} type.
*
* @return key type
* @since 2.2.0
*/
Class<?> keyType() default Object.class;

/**
* Sort values.
* The lower the value, the higher the priority.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,22 @@
*/
String key() default "";

/**
* <p>The type to which the key value of target should be converted
* when fetching the data source from the data source.
*
* <p>For example, the data source obtained from the data source
* is grouped according to the key of the {@link Long} type,
* and the key value corresponding to the current operation is {@link Integer},
* then the {@code keyType} needs to be {@link Long} at this time.<br />
* When the actual operation is performed,
* the key value is automatically converted from Integer to {@link Long} type.
*
* @return key type
* @since 2.2.0
*/
Class<?> keyType() default Object.class;

/**
* Sort values.
* The lower the value, the higher the priority.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import cn.crane4j.core.container.Container;
import cn.crane4j.core.executor.AssembleExecution;
import cn.crane4j.core.support.converter.ConverterManager;
import cn.crane4j.core.support.reflect.PropertyOperator;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
Expand Down Expand Up @@ -44,10 +45,13 @@ public class ManyToManyAssembleOperationHandler extends OneToManyAssembleOperati
* Create an {@link ManyToManyAssembleOperationHandler} instance.
*
* @param propertyOperator propertyOperator
* @param converterManager converter manager
* @param keySplitter splitter used to split the value of key attribute into multiple key values.
*/
public ManyToManyAssembleOperationHandler(PropertyOperator propertyOperator, Function<Object, Collection<Object>> keySplitter) {
super(propertyOperator);
public ManyToManyAssembleOperationHandler(
PropertyOperator propertyOperator, ConverterManager converterManager,
@NonNull Function<Object, Collection<Object>> keySplitter) {
super(propertyOperator, converterManager);
this.keySplitter = keySplitter;
}

Expand All @@ -56,9 +60,10 @@ public ManyToManyAssembleOperationHandler(PropertyOperator propertyOperator, Fun
* and use the default {@link DefaultSplitter} split key value
*
* @param propertyOperator property operator
* @param converterManager converter manager
*/
public ManyToManyAssembleOperationHandler(PropertyOperator propertyOperator) {
this(propertyOperator, new DefaultSplitter(","));
public ManyToManyAssembleOperationHandler(PropertyOperator propertyOperator, ConverterManager converterManager) {
this(propertyOperator, converterManager, new DefaultSplitter(","));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import cn.crane4j.core.parser.PropertyMapping;
import cn.crane4j.core.parser.handler.strategy.PropertyMappingStrategy;
import cn.crane4j.core.support.converter.ConverterManager;
import cn.crane4j.core.support.reflect.PropertyOperator;
import cn.crane4j.core.util.CollectionUtils;

Expand All @@ -27,9 +28,10 @@ public class OneToManyAssembleOperationHandler extends OneToOneAssembleOperation
* Create an {@link OneToManyAssembleOperationHandler} instance.
*
* @param propertyOperator property operator
* @param converterManager converter manager
*/
public OneToManyAssembleOperationHandler(PropertyOperator propertyOperator) {
super(propertyOperator);
public OneToManyAssembleOperationHandler(PropertyOperator propertyOperator, ConverterManager converterManager) {
super(propertyOperator, converterManager);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import cn.crane4j.core.executor.AssembleExecution;
import cn.crane4j.core.parser.PropertyMapping;
import cn.crane4j.core.parser.handler.strategy.PropertyMappingStrategy;
import cn.crane4j.core.support.converter.ConverterManager;
import cn.crane4j.core.support.reflect.PropertyOperator;
import cn.crane4j.core.util.StringUtils;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

import java.util.ArrayList;
Expand Down Expand Up @@ -33,6 +35,11 @@ public class OneToOneAssembleOperationHandler
*/
protected final PropertyOperator propertyOperator;

/**
* converter manager.
*/
private final ConverterManager converterManager;

/**
* Split the {@link AssembleExecution} into pending objects and wrap it as {@link Target}.
*
Expand All @@ -43,18 +50,32 @@ public class OneToOneAssembleOperationHandler
protected Collection<Target> collectToEntities(Collection<AssembleExecution> executions) {
List<Target> targets = new ArrayList<>();
for (AssembleExecution execution : executions) {
String key = execution.getOperation().getKey();
// TODO perhaps we need to use the key extractor as a standalone component in the AssembleOperation?
// if no key is specified, key value is the targets themselves.
UnaryOperator<Object> keyExtractor = StringUtils.isEmpty(key) ?
UnaryOperator.identity() : t -> propertyOperator.readProperty(t.getClass(), t, key);
UnaryOperator<Object> keyExtractor = getKeyExtractor(execution);
execution.getTargets().stream()
.map(t -> createTarget(execution, t, keyExtractor.apply(t)))
.forEach(targets::add);
}
return targets;
}

@NonNull
private UnaryOperator<Object> getKeyExtractor(AssembleExecution execution) {
String key = execution.getOperation().getKey();
// TODO perhaps we need to use the key extractor as a standalone component in the AssembleOperation?
// if no key is specified, key value is the targets themselves.
UnaryOperator<Object> keyExtractor = StringUtils.isEmpty(key) ?
UnaryOperator.identity() : t -> propertyOperator.readProperty(t.getClass(), t, key);
// fix https://github.com/opengoofy/crane4j/issues/153
Class<?> keyType = execution.getOperation().getKeyType();
if (Objects.nonNull(keyType)) {
return t -> {
Object k = keyExtractor.apply(t);
return converterManager.convert(k, keyType);
};
}
return keyExtractor;
}

/**
* Create a {@link Target} instance.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import cn.crane4j.core.support.AnnotationFinder;
import cn.crane4j.core.support.Crane4jGlobalConfiguration;
import cn.crane4j.core.support.Crane4jGlobalSorter;
import cn.crane4j.core.util.ClassUtils;
import cn.crane4j.core.util.CollectionUtils;
import cn.crane4j.core.util.ConfigurationUtil;
import cn.crane4j.core.util.MultiMap;
Expand Down Expand Up @@ -176,6 +177,7 @@ protected AssembleOperation createAssembleOperation(

// get configuration of standard assemble operation
String key = parseKey(element, standardAnnotation);
Class<?> keyType = parseKeyType(standardAnnotation, annotation);
AssembleOperationHandler assembleOperationHandler = parseAssembleOperationHandler(element, standardAnnotation);
Set<PropertyMapping> propertyMappings = parsePropertyMappings(element, standardAnnotation, key);
int sort = parseSort(element, standardAnnotation);
Expand All @@ -186,6 +188,7 @@ protected AssembleOperation createAssembleOperation(
AssembleOperation operation = createAssembleOperation(annotation, sort, key, assembleOperationHandler, propertyMappings);
operation.getGroups().addAll(groups);
operation.setPropertyMappingStrategy(propertyMappingStrategy);
operation.setKeyType(keyType);
return operation;
}

Expand Down Expand Up @@ -250,6 +253,7 @@ protected String parseKey(AnnotatedElement element, StandardAnnotation standardA
* @param standardAnnotation standard annotation
* @return assemble operation groups
*/
@SuppressWarnings("unused")
protected AssembleOperationHandler parseAssembleOperationHandler(
AnnotatedElement element, StandardAnnotation standardAnnotation) {
return globalConfiguration.getAssembleOperationHandler(
Expand Down Expand Up @@ -297,6 +301,7 @@ protected int parseSort(AnnotatedElement element, StandardAnnotation standardAnn
* @param standardAnnotation standard assemble operation
* @return groups
*/
@SuppressWarnings("unused")
protected Set<String> parseGroups(AnnotatedElement element, StandardAnnotation standardAnnotation) {
return Stream.of(standardAnnotation.getGroups())
.collect(Collectors.toSet());
Expand All @@ -310,6 +315,7 @@ protected Set<String> parseGroups(AnnotatedElement element, StandardAnnotation s
* @return {@link PropertyMappingStrategy} instance
* @since 2.1.0
*/
@SuppressWarnings("unused")
@NonNull
protected PropertyMappingStrategy parserPropertyMappingStrategy(
StandardAnnotation standardAnnotation, T annotation) {
Expand All @@ -330,6 +336,22 @@ protected PropertyMappingStrategy parserPropertyMappingStrategy(
return propertyMappingStrategy;
}

/**
* Parse key property type.
*
* @param standardAnnotation standard annotation
* @param annotation annotation
* @return key type
* @since 2.2.0
*/
@SuppressWarnings("unused")
@Nullable
protected Class<?> parseKeyType(
StandardAnnotation standardAnnotation, T annotation) {
Class<?> keyType = standardAnnotation.getKeyType();
return ClassUtils.isObjectOrVoid(keyType) ? null : keyType;
}

/**
* Standard annotation
*
Expand All @@ -345,6 +367,13 @@ public interface StandardAnnotation {
*/
String getKey();

/**
* Get key property type.
*
* @return key type
*/
Class<?> getKeyType();

/**
* <p>Sort values.
* The lower the value, the higher the priority.
Expand Down Expand Up @@ -409,6 +438,7 @@ public interface StandardAnnotation {
public static class StandardAnnotationAdapter implements StandardAnnotation {
private final Annotation annotation;
private final String key;
private final Class<?> keyType;
private final int sort;
private final String handler;
private final Class<?> handlerType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ protected String getContainerNamespace(Assemble annotation) {
protected StandardAnnotation getStandardAnnotation(
BeanOperations beanOperations, AnnotatedElement element, Assemble annotation) {
return new StandardAnnotationAdapter(
annotation, annotation.key(), annotation.sort(),
annotation, annotation.key(), annotation.keyType(), annotation.sort(),
annotation.handler(), annotation.handlerType(),
annotation.propTemplates(), annotation.props(), annotation.groups(),
annotation.propertyMappingStrategy()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import java.lang.reflect.AnnotatedElement;
import java.util.Comparator;
import java.util.Objects;
import java.util.Set;

/**
Expand Down Expand Up @@ -110,7 +109,7 @@ protected String determineNamespace(AssembleEnum annotation) {
@SuppressWarnings("unchecked")
private Class<? extends Enum<?>> resolveEnumType(AssembleEnum annotation) {
Class<?> type = annotation.type();
if (Objects.equals(type, Object.class) || Objects.equals(type, Void.TYPE)) {
if (ClassUtils.isObjectOrVoid(type)) {
type = ClassUtils.forName(annotation.typeName(), type);
Asserts.isTrue(type.isEnum(), "type [{}] which specified in @AssembleEnum is not a enum type", type.getName());
}
Expand All @@ -129,7 +128,7 @@ private Class<? extends Enum<?>> resolveEnumType(AssembleEnum annotation) {
protected StandardAnnotation getStandardAnnotation(
BeanOperations beanOperations, AnnotatedElement element, AssembleEnum annotation) {
return new StandardAnnotationAdapter(
annotation, annotation.key(), annotation.sort(),
annotation, annotation.key(), annotation.keyType(), annotation.sort(),
annotation.handler(), annotation.handlerType(),
annotation.propTemplates(), annotation.props(), annotation.groups(),
annotation.propertyMappingStrategy()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ protected String determineNamespace(AssembleMethod annotation) {
protected StandardAnnotation getStandardAnnotation(
BeanOperations beanOperations, AnnotatedElement element, AssembleMethod annotation) {
return new StandardAnnotationAdapter(
annotation, annotation.key(), annotation.sort(),
annotation, annotation.key(), annotation.keyType(), annotation.sort(),
annotation.handler(), annotation.handlerType(),
annotation.propTemplates(), annotation.props(), annotation.groups(),
annotation.propertyMappingStrategy()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import cn.crane4j.core.support.Crane4jGlobalConfiguration;
import cn.crane4j.core.support.Crane4jGlobalSorter;
import cn.crane4j.core.support.Sorted;
import cn.crane4j.core.util.ClassUtils;
import cn.crane4j.core.util.ReflectUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -26,7 +27,6 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand Down Expand Up @@ -132,7 +132,7 @@ protected DisassembleOperation createDisassembleOperation(

// wait until runtime to dynamically determine the actual type if no type is specified
DisassembleOperation operation;
if (Objects.equals(Object.class, annotation.type()) || Objects.equals(Void.TYPE, annotation.type())) {
if (ClassUtils.isObjectOrVoid(annotation.type())) {
operation = new TypeDynamitedDisassembleOperation(
key, sort, type, disassembleOperationHandler, parser, globalConfiguration.getTypeResolver()
);
Expand Down
Loading

0 comments on commit 0a6cee5

Please sign in to comment.