From 08509b575a4caa5bd0ddf88115f764425e0b209b Mon Sep 17 00:00:00 2001 From: chentaoah <609580885@qq.com> Date: Sat, 26 Mar 2022 16:55:00 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=BB=A3=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E7=BB=91=E5=AE=9A=E5=85=B3=E7=B3=BB=E5=8F=AF=E4=BB=A5=E6=98=AF?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/proxy/annotation/Binding.java | 15 ++++ .../domain/proxy/annotation/Bindings.java | 13 +++ .../domain/proxy/annotation/Entity.java | 6 -- .../proxy/entity/BindingDefinition.java | 15 ++++ .../domain/proxy/entity/EntityDefinition.java | 4 +- .../AbstractEntityDefinitionResolver.java | 67 ++++++++++----- .../proxy/impl/AbstractGenericRepository.java | 86 +++++++++++-------- .../domain/proxy/utils/CollectionUtils.java | 22 +++++ 8 files changed, 163 insertions(+), 65 deletions(-) create mode 100644 spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/annotation/Binding.java create mode 100644 spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/annotation/Bindings.java create mode 100644 spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/entity/BindingDefinition.java create mode 100644 spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/utils/CollectionUtils.java diff --git a/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/annotation/Binding.java b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/annotation/Binding.java new file mode 100644 index 00000000..af63bcd8 --- /dev/null +++ b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/annotation/Binding.java @@ -0,0 +1,15 @@ +package com.gitee.spring.domain.proxy.annotation; + +import java.lang.annotation.*; + +@Inherited +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.FIELD}) +public @interface Binding { + + String field(); + + String bind(); + +} diff --git a/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/annotation/Bindings.java b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/annotation/Bindings.java new file mode 100644 index 00000000..7598cdd9 --- /dev/null +++ b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/annotation/Bindings.java @@ -0,0 +1,13 @@ +package com.gitee.spring.domain.proxy.annotation; + +import java.lang.annotation.*; + +@Inherited +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.FIELD}) +public @interface Bindings { + + Binding[] value(); + +} diff --git a/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/annotation/Entity.java b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/annotation/Entity.java index 43d0f623..b56a7df3 100644 --- a/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/annotation/Entity.java +++ b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/annotation/Entity.java @@ -16,12 +16,6 @@ public @interface Entity { boolean manyToOne() default false; - boolean useContext() default false; - - String queryField() default "relationId"; - - String queryValue() default "/id"; - Class assembler() default DefaultEntityAssembler.class; } diff --git a/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/entity/BindingDefinition.java b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/entity/BindingDefinition.java new file mode 100644 index 00000000..3f41a086 --- /dev/null +++ b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/entity/BindingDefinition.java @@ -0,0 +1,15 @@ +package com.gitee.spring.domain.proxy.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import org.springframework.core.annotation.AnnotationAttributes; + +@Data +@Builder +@AllArgsConstructor +public class BindingDefinition { + private AnnotationAttributes attributes; + private boolean fromContext; + private EntityPropertyChain bindEntityPropertyChain; +} diff --git a/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/entity/EntityDefinition.java b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/entity/EntityDefinition.java index b0980fa2..de696f34 100644 --- a/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/entity/EntityDefinition.java +++ b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/entity/EntityDefinition.java @@ -6,6 +6,8 @@ import lombok.Builder; import lombok.Data; import org.springframework.core.annotation.AnnotationAttributes; +import java.util.List; + @Data @Builder @AllArgsConstructor @@ -15,6 +17,6 @@ public class EntityDefinition { private AnnotationAttributes attributes; private Object mapper; private Class pojoClass; - private EntityPropertyChain queryValueEntityPropertyChain; private EntityAssembler entityAssembler; + private List bindingDefinitions; } diff --git a/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/impl/AbstractEntityDefinitionResolver.java b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/impl/AbstractEntityDefinitionResolver.java index 267a5d87..8501f111 100644 --- a/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/impl/AbstractEntityDefinitionResolver.java +++ b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/impl/AbstractEntityDefinitionResolver.java @@ -1,8 +1,10 @@ package com.gitee.spring.domain.proxy.impl; import cn.hutool.core.lang.Assert; +import com.gitee.spring.domain.proxy.annotation.Binding; import com.gitee.spring.domain.proxy.annotation.Entity; import com.gitee.spring.domain.proxy.api.EntityAssembler; +import com.gitee.spring.domain.proxy.entity.BindingDefinition; import com.gitee.spring.domain.proxy.entity.EntityDefinition; import com.gitee.spring.domain.proxy.entity.EntityPropertyChain; import com.gitee.spring.domain.proxy.utils.ReflectUtils; @@ -12,6 +14,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Constructor; @@ -24,10 +27,9 @@ public abstract class AbstractEntityDefinitionResolver implements ApplicationCon public static final String MAPPER_ATTRIBUTES = "mapper"; public static final String IGNORED_ON_ATTRIBUTES = "ignoredOn"; public static final String MANY_TO_ONE_ATTRIBUTES = "manyToOne"; - public static final String USE_CONTEXT_ATTRIBUTES = "useContext"; - public static final String QUERY_FIELD_ATTRIBUTES = "queryField"; - public static final String QUERY_VALUE_ATTRIBUTES = "queryValue"; public static final String ASSEMBLER_ATTRIBUTES = "assembler"; + public static final String FIELD_ATTRIBUTES = "field"; + public static final String BIND_ATTRIBUTES = "bind"; protected ApplicationContext applicationContext; protected Class entityClass; @@ -48,21 +50,33 @@ public abstract class AbstractEntityDefinitionResolver implements ApplicationCon Type actualTypeArgument = parameterizedType.getActualTypeArguments()[0]; entityClass = (Class) actualTypeArgument; constructor = ReflectUtils.getConstructor(entityClass, null); + AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(entityClass, Entity.class); - visitEntityClass(null, entityClass, entityClass, attributes, "/", null); + Set bindingAnnotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(entityClass, Binding.class); + visitEntityClass(null, entityClass, entityClass, attributes, bindingAnnotations, "/", null); + entityDefinitionMap.values().forEach(entityDefinition -> { EntityPropertyChain entityPropertyChain = entityDefinition.getEntityPropertyChain(); entityPropertyChain.initialize(); - EntityPropertyChain queryValueEntityPropertyChain = entityDefinition.getQueryValueEntityPropertyChain(); - queryValueEntityPropertyChain.initialize(); + for (BindingDefinition bindingDefinition : entityDefinition.getBindingDefinitions()) { + if (!bindingDefinition.isFromContext()) { + EntityPropertyChain bindEntityPropertyChain = bindingDefinition.getBindEntityPropertyChain(); + bindEntityPropertyChain.initialize(); + } + } }); } - protected void visitEntityClass(Class lastEntityClass, Class entityClass, Class genericEntityClass, - AnnotationAttributes attributes, String accessPath, String fieldName) { + protected void visitEntityClass(Class lastEntityClass, + Class entityClass, + Class genericEntityClass, + AnnotationAttributes attributes, + Set bindingAnnotations, + String accessPath, + String fieldName) { EntityPropertyChain entityPropertyChain = newEntityPropertyChain(lastEntityClass, entityClass, accessPath, fieldName); if (attributes != null) { - EntityDefinition entityDefinition = newEntityDefinition(entityPropertyChain, entityClass, genericEntityClass, attributes); + EntityDefinition entityDefinition = newEntityDefinition(entityPropertyChain, entityClass, genericEntityClass, attributes, bindingAnnotations); if (lastEntityClass == null) { rootEntityDefinition = entityDefinition; } else { @@ -79,13 +93,17 @@ public abstract class AbstractEntityDefinitionResolver implements ApplicationCon fieldGenericEntityClass = (Class) actualTypeArgument; } AnnotationAttributes fieldAttributes = AnnotatedElementUtils.getMergedAnnotationAttributes(field, Entity.class); + Set fieldBindingAnnotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(field, Binding.class); String fieldAccessPath = "/".equals(accessPath) ? accessPath + field.getName() : accessPath + "/" + field.getName(); - visitEntityClass(entityClass, fieldEntityClass, fieldGenericEntityClass, fieldAttributes, fieldAccessPath, field.getName()); + visitEntityClass(entityClass, fieldEntityClass, fieldGenericEntityClass, fieldAttributes, fieldBindingAnnotations, fieldAccessPath, field.getName()); }); } } - protected EntityPropertyChain newEntityPropertyChain(Class lastEntityClass, Class entityClass, String accessPath, String fieldName) { + protected EntityPropertyChain newEntityPropertyChain(Class lastEntityClass, + Class entityClass, + String accessPath, + String fieldName) { if (lastEntityClass == null) return null; String lastAccessPath = accessPath.lastIndexOf("/") > 0 ? accessPath.substring(0, accessPath.lastIndexOf("/")) : "/"; EntityPropertyChain lastEntityPropertyChain = entityPropertyChainMap.get(lastAccessPath); @@ -97,7 +115,8 @@ public abstract class AbstractEntityDefinitionResolver implements ApplicationCon protected EntityDefinition newEntityDefinition(EntityPropertyChain entityPropertyChain, Class entityClass, Class genericEntityClass, - AnnotationAttributes attributes) { + AnnotationAttributes attributes, + Set bindingAnnotations) { Class mapperClass = attributes.getClass(MAPPER_ATTRIBUTES); Object mapper = applicationContext.getBean(mapperClass); Type targetType = mapperClass.getGenericInterfaces()[0]; @@ -108,18 +127,24 @@ public abstract class AbstractEntityDefinitionResolver implements ApplicationCon attributes.put(MANY_TO_ONE_ATTRIBUTES, true); } - EntityPropertyChain queryValueEntityPropertyChain = null; - if (entityPropertyChain != null && !attributes.getBoolean(USE_CONTEXT_ATTRIBUTES)) { - String queryValue = attributes.getString(QUERY_VALUE_ATTRIBUTES); - queryValueEntityPropertyChain = entityPropertyChainMap.get(queryValue); - Assert.notNull(queryValueEntityPropertyChain, "Query value location not available!"); - } - Class assemblerClass = attributes.getClass(ASSEMBLER_ATTRIBUTES); EntityAssembler entityAssembler = (EntityAssembler) applicationContext.getBean(assemblerClass); - return new EntityDefinition(entityPropertyChain, genericEntityClass, - attributes, mapper, pojoClass, queryValueEntityPropertyChain, entityAssembler); + List bindingDefinitions = new ArrayList<>(); + for (Binding bindingAnnotation : bindingAnnotations) { + AnnotationAttributes bindingAttributes = AnnotationUtils.getAnnotationAttributes(bindingAnnotation, false, false); + String bind = bindingAttributes.getString(BIND_ATTRIBUTES); + if (bind.startsWith("/")) { + EntityPropertyChain bindEntityPropertyChain = entityPropertyChainMap.get(bind); + Assert.notNull(bindEntityPropertyChain, "Bound path not available!"); + bindingDefinitions.add(new BindingDefinition(bindingAttributes, false, bindEntityPropertyChain)); + } else { + bindingDefinitions.add(new BindingDefinition(bindingAttributes, true, null)); + } + } + + return new EntityDefinition(entityPropertyChain, genericEntityClass, attributes, + mapper, pojoClass, entityAssembler, bindingDefinitions); } protected boolean filterEntityClass(Class entityClass) { diff --git a/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/impl/AbstractGenericRepository.java b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/impl/AbstractGenericRepository.java index 6d411ee1..22a7c91c 100644 --- a/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/impl/AbstractGenericRepository.java +++ b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/impl/AbstractGenericRepository.java @@ -4,15 +4,15 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.lang.Assert; import com.gitee.spring.domain.proxy.api.EntityAssembler; import com.gitee.spring.domain.proxy.api.EntityProperty; -import com.gitee.spring.domain.proxy.entity.BoundedContext; -import com.gitee.spring.domain.proxy.entity.EntityDefinition; -import com.gitee.spring.domain.proxy.entity.EntityPropertyChain; -import com.gitee.spring.domain.proxy.entity.RepositoryContext; +import com.gitee.spring.domain.proxy.entity.*; +import com.gitee.spring.domain.proxy.utils.CollectionUtils; import com.gitee.spring.domain.proxy.utils.ReflectUtils; import org.springframework.core.annotation.AnnotationAttributes; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; public abstract class AbstractGenericRepository extends AbstractRepository { @@ -27,7 +27,7 @@ public abstract class AbstractGenericRepository extends AbstractRepositor rootEntity = (E) entityAssembler.assemble(boundedContext, null, rootEntityDefinition, persistentObject); } } else { - rootEntity = newInstance(boundedContext, primaryKey); + rootEntity = (E) ReflectUtils.newInstance(constructor, null); } if (rootEntity != null) { handleRootEntity(boundedContext, rootEntity); @@ -36,11 +36,6 @@ public abstract class AbstractGenericRepository extends AbstractRepositor return null; } - @SuppressWarnings("unchecked") - protected E newInstance(BoundedContext boundedContext, PK primaryKey) { - return (E) ReflectUtils.newInstance(constructor, null); - } - protected void handleRootEntity(BoundedContext boundedContext, E rootEntity) { if (rootEntity instanceof RepositoryContext) { RepositoryContext repositoryContext = (RepositoryContext) rootEntity; @@ -54,23 +49,31 @@ public abstract class AbstractGenericRepository extends AbstractRepositor if (lastEntity != null) { AnnotationAttributes attributes = entityDefinition.getAttributes(); String[] ignoredOnStrs = attributes.getStringArray(IGNORED_ON_ATTRIBUTES); + boolean isIgnore = false; for (String ignoredOn : ignoredOnStrs) { if (boundedContext.containsKey(ignoredOn)) { - return; + isIgnore = true; + break; } } - Object persistentObject = null; - if (attributes.getBoolean(USE_CONTEXT_ATTRIBUTES)) { - persistentObject = doSelectByContext(entityDefinition.getMapper(), boundedContext, - attributes.getBoolean(MANY_TO_ONE_ATTRIBUTES)); - } else { - EntityPropertyChain queryValueEntityPropertyChain = entityDefinition.getQueryValueEntityPropertyChain(); - Object queryValue = queryValueEntityPropertyChain.getValue(rootEntity); - if (queryValue != null) { - persistentObject = doSelectByQueryField(entityDefinition.getMapper(), boundedContext, - attributes.getBoolean(MANY_TO_ONE_ATTRIBUTES), attributes.getString(QUERY_FIELD_ATTRIBUTES), queryValue); + if (isIgnore) { + continue; + } + Map queryParams = new LinkedHashMap<>(); + for (BindingDefinition bindingDefinition : entityDefinition.getBindingDefinitions()) { + String field = bindingDefinition.getAttributes().getString(FIELD_ATTRIBUTES); + if (bindingDefinition.isFromContext()) { + String bind = bindingDefinition.getAttributes().getString(BIND_ATTRIBUTES); + Object bindValue = boundedContext.get(bind); + queryParams.put(field, bindValue); + } else { + EntityPropertyChain bindEntityPropertyChain = bindingDefinition.getBindEntityPropertyChain(); + Object bindValue = bindEntityPropertyChain.getValue(rootEntity); + queryParams.put(field, bindValue); } } + Object persistentObject = doSelectByExample(entityDefinition.getMapper(), boundedContext, + attributes.getBoolean(MANY_TO_ONE_ATTRIBUTES), queryParams); if (persistentObject != null) { EntityAssembler entityAssembler = entityDefinition.getEntityAssembler(); Object entity = entityAssembler.assemble(boundedContext, rootEntity, entityDefinition, persistentObject); @@ -87,7 +90,7 @@ public abstract class AbstractGenericRepository extends AbstractRepositor @SuppressWarnings("unchecked") public List findByExample(BoundedContext boundedContext, Object example) { Assert.notNull(rootEntityDefinition, "Aggregation root is not annotated by @Entity, please use the [findByPrimaryKey] method."); - Object persistentObject = doSelectByExample(rootEntityDefinition.getMapper(), boundedContext, example); + Object persistentObject = doSelectByExample(rootEntityDefinition.getMapper(), boundedContext, true, example); if (persistentObject != null) { EntityAssembler entityAssembler = rootEntityDefinition.getEntityAssembler(); List rootEntities = (List) entityAssembler.assemble(boundedContext, null, rootEntityDefinition, persistentObject); @@ -107,31 +110,44 @@ public abstract class AbstractGenericRepository extends AbstractRepositor Object persistentObject = entityAssembler.disassemble(boundedContext, entity, rootEntityDefinition, entity); if (persistentObject != null) { doInsert(rootEntityDefinition.getMapper(), boundedContext, persistentObject); + copyPrimaryKeyForEntity(entity, persistentObject); } } for (EntityDefinition entityDefinition : entityDefinitionMap.values()) { EntityPropertyChain entityPropertyChain = entityDefinition.getEntityPropertyChain(); Object targetEntity = entityPropertyChain.getValue(entity); if (targetEntity != null) { + bindRelationIdForEntity(entityDefinition, boundedContext, entity, targetEntity); EntityAssembler entityAssembler = entityDefinition.getEntityAssembler(); Object persistentObject = entityAssembler.disassemble(boundedContext, entity, entityDefinition, targetEntity); if (persistentObject != null) { - bindRelationIdForEntity(entityDefinition, entity, targetEntity, persistentObject); doInsert(entityDefinition.getMapper(), boundedContext, persistentObject); - Object primaryKey = BeanUtil.getFieldValue(persistentObject, "id"); - BeanUtil.setFieldValue(entity, "id", primaryKey); + copyPrimaryKeyForEntity(entity, persistentObject); } } } } - protected void bindRelationIdForEntity(EntityDefinition entityDefinition, Object rootEntity, Object entity, Object persistentObject) { - AnnotationAttributes attributes = entityDefinition.getAttributes(); - if (!attributes.getBoolean(USE_CONTEXT_ATTRIBUTES)) { - EntityPropertyChain queryValueEntityPropertyChain = entityDefinition.getQueryValueEntityPropertyChain(); - Object queryValue = queryValueEntityPropertyChain.getValue(rootEntity); - if (queryValue != null) { - BeanUtil.setFieldValue(entity, attributes.getString(QUERY_FIELD_ATTRIBUTES), queryValue); + protected void copyPrimaryKeyForEntity(Object entity, Object persistentObject) { + if (!(entity instanceof List)) { + Object primaryKey = BeanUtil.getFieldValue(persistentObject, "id"); + BeanUtil.setFieldValue(entity, "id", primaryKey); + } + } + + protected void bindRelationIdForEntity(EntityDefinition entityDefinition, BoundedContext boundedContext, Object rootEntity, Object entity) { + for (BindingDefinition bindingDefinition : entityDefinition.getBindingDefinitions()) { + String field = bindingDefinition.getAttributes().getString(FIELD_ATTRIBUTES); + Object bindValue; + if (bindingDefinition.isFromContext()) { + String bind = bindingDefinition.getAttributes().getString(BIND_ATTRIBUTES); + bindValue = boundedContext.get(bind); + } else { + EntityPropertyChain bindEntityPropertyChain = bindingDefinition.getBindEntityPropertyChain(); + bindValue = bindEntityPropertyChain.getValue(rootEntity); + } + if (bindValue != null) { + CollectionUtils.forEach(entity, eachEntity -> BeanUtil.setFieldValue(eachEntity, field, bindValue)); } } } @@ -170,11 +186,7 @@ public abstract class AbstractGenericRepository extends AbstractRepositor protected abstract Object doSelectByPrimaryKey(Object mapper, BoundedContext boundedContext, PK primaryKey); - protected abstract Object doSelectByExample(Object mapper, BoundedContext boundedContext, Object example); - - protected abstract Object doSelectByContext(Object mapper, BoundedContext boundedContext, boolean manyToOne); - - protected abstract Object doSelectByQueryField(Object mapper, BoundedContext boundedContext, boolean manyToOne, String queryField, Object queryValue); + protected abstract Object doSelectByExample(Object mapper, BoundedContext boundedContext, boolean manyToOne, Object example); protected abstract void doInsert(Object mapper, BoundedContext boundedContext, Object persistentObject); diff --git a/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/utils/CollectionUtils.java b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/utils/CollectionUtils.java new file mode 100644 index 00000000..26a81e03 --- /dev/null +++ b/spring-domain-proxy/src/main/java/com/gitee/spring/domain/proxy/utils/CollectionUtils.java @@ -0,0 +1,22 @@ +package com.gitee.spring.domain.proxy.utils; + +import java.util.List; +import java.util.function.Consumer; + +public class CollectionUtils { + + @SuppressWarnings("unchecked") + public static void forEach(Object object, Consumer consumer) { + if (object != null) { + if (object instanceof List) { + List list = (List) object; + for (T item : list) { + consumer.accept(item); + } + } else { + consumer.accept((T) object); + } + } + } + +} -- Gitee