Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(KeyResolver): Support specifying key resolver for assemble opera…
Browse files Browse the repository at this point in the history
…tions (GitHub #222,#103, Gitee #I8XPFW)
Createsequence committed Mar 4, 2024
1 parent de84a38 commit 7622bdf
Showing 38 changed files with 1,022 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -142,6 +142,23 @@
* @since 2.2.0
*/
Class<?> keyType() default Object.class;

/**
* The name of key resolver to be used.
*
* @return namespace
* @since 2.7.0
*/
String keyResolver() default "";

/**
* Some description of the key which
* helps {@link #keyResolver() resolver} to resolve the key.
*
* @return description
* @since 2.7.0
*/
String keyDescription() default "";

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

/**
* The name of key resolver to be used.
*
* @return namespace
* @since 2.7.0
*/
String keyResolver() default "";

/**
* Some description of the key which
* helps {@link #keyResolver() resolver} to resolve the key.
*
* @return description
* @since 2.7.0
*/
String keyDescription() default "";

/**
* <p>The type to which the key value of target should be converted
* when fetching the data source from the data source.
Original file line number Diff line number Diff line change
@@ -99,6 +99,23 @@
*/
String key() default "";

/**
* The name of key resolver to be used.
*
* @return namespace
* @since 2.7.0
*/
String keyResolver() default "";

/**
* Some description of the key which
* helps {@link #keyResolver() resolver} to resolve the key.
*
* @return description
* @since 2.7.0
*/
String keyDescription() default "";

/**
* <p>The type to which the key value of target should be converted
* when fetching the data source from the data source.
Original file line number Diff line number Diff line change
@@ -115,6 +115,23 @@
*/
Class<?> keyType() default Object.class;

/**
* The name of key resolver to be used.
*
* @return namespace
* @since 2.7.0
*/
String keyResolver() default "";

/**
* Some description of the key which
* helps {@link #keyResolver() resolver} to resolve the key.
*
* @return description
* @since 2.7.0
*/
String keyDescription() default "";

/**
* Sort values.
* The lower the value, the higher the priority.
Original file line number Diff line number Diff line change
@@ -108,6 +108,23 @@
*/
Class<?> keyType() default Object.class;

/**
* The name of key resolver to be used.
*
* @return namespace
* @since 2.7.0
*/
String keyResolver() default "";

/**
* Some description of the key which
* helps {@link #keyResolver() resolver} to resolve the key.
*
* @return description
* @since 2.7.0
*/
String keyDescription() default "";

/**
* Sort values.
* The lower the value, the higher the priority.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cn.crane4j.core.container.lifecycle;

import cn.crane4j.annotation.OperationAwareBean;
import cn.crane4j.core.executor.OperationAwareBeanOperationExecutor;
import cn.crane4j.core.executor.AbstractOperationAwareBeanOperationExecutor;
import cn.crane4j.core.parser.BeanOperations;
import cn.crane4j.core.parser.operation.KeyTriggerOperation;

@@ -10,7 +10,7 @@
* It's enhanced on the basis of {@link OperationAwareBean} and supports awareness more arguments.
*
* @author huangchengxing
* @see OperationAwareBeanOperationExecutor
* @see AbstractOperationAwareBeanOperationExecutor
* @since 2.5.0
*/
public interface SmartOperationAwareBean extends OperationAwareBean {
Original file line number Diff line number Diff line change
@@ -59,7 +59,7 @@
* it is recommended to minimize the number of accesses to the {@link Container}.
*
* @author huangchengxing
* @see OperationAwareBeanOperationExecutor
* @see AbstractOperationAwareBeanOperationExecutor
* @see AsyncBeanOperationExecutor
* @see DisorderedBeanOperationExecutor
* @see OrderedBeanOperationExecutor
@@ -245,6 +245,7 @@ protected void beforeAssembleOperation(MultiMap<BeanOperations, Object> targetWi
* @param options options for execution
* @since 2.5.0
*/
@SuppressWarnings("unused")
protected void beforeDisassembleOperation(
Collection<?> targets, BeanOperations operations, Options options) {
// do nothing
Original file line number Diff line number Diff line change
@@ -23,9 +23,9 @@
* @see SmartOperationAwareBean
* @since 2.5.0
*/
public abstract class OperationAwareBeanOperationExecutor extends AbstractBeanOperationExecutor {
public abstract class AbstractOperationAwareBeanOperationExecutor extends AbstractBeanOperationExecutor {

protected OperationAwareBeanOperationExecutor(ContainerManager containerManager) {
protected AbstractOperationAwareBeanOperationExecutor(ContainerManager containerManager) {
super(containerManager);
}

Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@
* @author huangchengxing
*/
@Slf4j
public class DisorderedBeanOperationExecutor extends OperationAwareBeanOperationExecutor {
public class DisorderedBeanOperationExecutor extends AbstractOperationAwareBeanOperationExecutor {

/**
* Create an instance of {@link DisorderedBeanOperationExecutor}.
@@ -55,7 +55,7 @@ protected void executeOperations(List<AssembleExecution> executions, Options opt
Map<Container<?>, Map<AssembleOperationHandler, List<AssembleExecution>>> operations = new LinkedHashMap<>();
executions.forEach(e -> {
Container<?> container = e.getContainer();
Map<AssembleOperationHandler, List<AssembleExecution>> he = operations.computeIfAbsent(container, c -> new HashMap<>());
Map<AssembleOperationHandler, List<AssembleExecution>> he = operations.computeIfAbsent(container, c -> new HashMap<>(8));
List<AssembleExecution> es = he.computeIfAbsent(e.getHandler(), h -> new ArrayList<>());
es.add(e);
});
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
*
* @author huangchengxing
*/
public class OrderedBeanOperationExecutor extends OperationAwareBeanOperationExecutor {
public class OrderedBeanOperationExecutor extends AbstractOperationAwareBeanOperationExecutor {

/**
* comparator
Original file line number Diff line number Diff line change
@@ -30,14 +30,14 @@
* @author huangchengxing
* @see DefaultSplitter
*/
@Setter
public class ManyToManyAssembleOperationHandler extends OneToManyAssembleOperationHandler {

/**
* splitter used to split the value of key attribute into multiple key values.
*
* @see ManyToManyAssembleOperationHandler.DefaultSplitter
*/
@Setter
@NonNull
private KeySplitter keySplitter;

@@ -76,6 +76,7 @@ public ManyToManyAssembleOperationHandler(PropertyOperator propertyOperator, Con
*/
@Override
protected Target createTarget(AssembleExecution execution, Object origin, Object keyValue) {
// TODO remove this override method in the future, the KeyResolver already split the key value
return new Target(execution, origin, keySplitter.apply(keyValue));
}

Original file line number Diff line number Diff line change
@@ -2,8 +2,10 @@

import cn.crane4j.core.container.Container;
import cn.crane4j.core.executor.AssembleExecution;
import cn.crane4j.core.executor.key.KeyResolver;
import cn.crane4j.core.parser.PropertyMapping;
import cn.crane4j.core.parser.handler.strategy.PropertyMappingStrategy;
import cn.crane4j.core.parser.operation.AssembleOperation;
import cn.crane4j.core.support.converter.ConverterManager;
import cn.crane4j.core.support.reflect.PropertyOperator;
import cn.crane4j.core.util.StringUtils;
@@ -17,7 +19,6 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

/**
@@ -57,31 +58,37 @@ public class OneToOneAssembleOperationHandler
protected Collection<Target> collectToEntities(Collection<AssembleExecution> executions) {
List<Target> targets = new ArrayList<>();
for (AssembleExecution execution : executions) {
UnaryOperator<Object> keyExtractor = getKeyExtractor(execution);
AssembleOperation operation = execution.getOperation();
KeyResolver keyResolver = getKeyResolver(execution);
execution.getTargets().stream()
.map(t -> createTarget(execution, t, keyExtractor.apply(t)))
.map(t -> createTarget(execution, t, keyResolver.resolve(t, operation)))
.filter(t -> !ignoreNullKey || Objects.nonNull(t.getKey()))
.forEach(targets::add);
}
return targets;
}

@NonNull
private UnaryOperator<Object> getKeyExtractor(AssembleExecution execution) {
private KeyResolver getKeyResolver(AssembleExecution execution) {
KeyResolver keyResolver = execution.getOperation().getKeyResolver();
if (Objects.nonNull(keyResolver)) {
return keyResolver;
}
// TODO remove this branch in the future, the KeyResolver will be required.
return getDefaultKeyPropertyResolver(execution);
}

private KeyResolver getDefaultKeyPropertyResolver(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);
KeyResolver keyResolver = StringUtils.isEmpty(key) ?
(t, op) -> t : (t, op) -> 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;
return Objects.isNull(keyType) ? keyResolver : (op, t) -> {
Object k = keyResolver.resolve(op, t);
return converterManager.convert(k, keyType);
};
}

/**
@@ -140,7 +147,7 @@ protected void completeMapping(Object source, Target target) {
}
}

private void mappingProperty(Target entity, Object source,PropertyMapping mapping) {
private void mappingProperty(Target entity, Object source, PropertyMapping mapping) {
PropertyMappingStrategy propertyMappingStrategy = entity.getExecution().getOperation().getPropertyMappingStrategy();
Object sourceValue = mapping.hasSource() ?
propertyOperator.readProperty(source.getClass(), source, mapping.getSource()) : source;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package cn.crane4j.core.executor.key;

import java.util.HashMap;
import java.util.Map;

/**
* <p>Default key resolver registry
*
* @author huangchengxing
* @since 2.7.0
*/
public class DefaultKeyResolverProviderRegistry implements KeyResolverRegistry {

private final Map<String, KeyResolverProvider> providers = new HashMap<>();

@Override
public void register(String name, KeyResolverProvider resolverProvider) {
providers.put(name, resolverProvider);
}

@Override
public KeyResolverProvider getKeyResolver(String name) {
return providers.get(name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cn.crane4j.core.executor.key;

import cn.crane4j.core.parser.operation.AssembleOperation;

/**
* <p>Key resolver, which is used to resolve the key of the operation.
*
* @author huangchengxing
* @since 2.7.0
*/
public interface KeyResolver extends KeyResolverProvider {

/**
* Get the resolver of the operation.
*
* @param operation operation
* @return resolver
*/
@Override
default KeyResolver getResolver(AssembleOperation operation) {
return this;
}

/**
* Resolve the key of the operation.
*
* @param target target
* @param operation operation
* @return key
*/
Object resolve(Object target, AssembleOperation operation);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cn.crane4j.core.executor.key;

import cn.crane4j.core.parser.operation.AssembleOperation;

/**
* <p>Key resolver provider
*
* @author huangchengxing
* @since 2.7.0
*/
public interface KeyResolverProvider {

/**
* Get the resolver of the operation.
*
* @param operation operation
* @return resolver
*/
KeyResolver getResolver(AssembleOperation operation);
}
Loading

0 comments on commit 7622bdf

Please sign in to comment.