com.kasinf.framework.rest.util.ProjectionUtils Maven / Gradle / Ivy
package com.kasinf.framework.rest.util;
import com.kasinf.framework.rest.annotation.Projection;
import lombok.AccessLevel;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.util.ProxyUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author lkhsh
* 投影工具栏类,借用SpringData Rest中的方法
*/
public final class ProjectionUtils {
private static final String PROJECTION_ANNOTATION_NOT_FOUND = "在%s上找不到投影注解!手动添加注解或手动将源类型添加到注册中!";
private final static Set PROJECTION_DEFINITIONS = new HashSet<>();
/**
* 添加投影关系
*
* @param projectionType 投影类型
*/
public static void addProjection(Class> projectionType) {
Assert.notNull(projectionType, "Projection的类型不能为null");
Projection annotation = AnnotationUtils.findAnnotation(projectionType, Projection.class);
if (annotation == null) {
throw new IllegalArgumentException(String.format(PROJECTION_ANNOTATION_NOT_FOUND, projectionType));
}
String name = annotation.name();
Class>[] sourceTypes = annotation.types();
if (StringUtils.hasText(name)) {
addProjection(projectionType, name, sourceTypes);
} else {
addProjection(projectionType, sourceTypes);
}
}
/**
* 添加投影
*
* @param projectionType must not be {@literal null}.
* @param sourceTypes must not be {@literal null} or empty.
*/
public static void addProjection(Class> projectionType, Class>... sourceTypes) {
Assert.notNull(projectionType, "Projection的类型不能为null");
addProjection(projectionType, StringUtils.uncapitalize(projectionType.getSimpleName()), sourceTypes);
}
/**
* 添加投影
*
* @param projectionType must not be {@literal null}.
* @param name must not be {@literal null} or empty.
* @param sourceTypes must not be {@literal null} or empty.
*/
public static void addProjection(Class> projectionType, String name, Class>... sourceTypes) {
Assert.notNull(projectionType, "Projection的类型不能为null");
Assert.hasText(name, "Name不能为null或空");
Assert.notEmpty(sourceTypes, "源类型不能为null");
for (Class> sourceType : sourceTypes) {
PROJECTION_DEFINITIONS.add(ProjectionDefinition.of(sourceType, projectionType, name));
}
}
/**
* 判断目标类型是否有注册的投影
*
* @param sourceType 元类型
* @return boolean
*/
public static boolean hasProjectionFor(Class> sourceType) {
for (ProjectionDefinition definition : PROJECTION_DEFINITIONS) {
if (definition.sourceType.isAssignableFrom(sourceType)) {
return true;
}
}
return false;
}
/**
* 获取目标类型的投影
*
* @param sourceType 源类型
* @param name 投影名称
* @return Class
*/
public static Class> getProjectionType(Class> sourceType, String name) {
return getProjectionsFor(sourceType).get(name);
}
/**
* 返回所有目标类型注册的投影
*
* @param sourceType must not be {@literal null}.
* @return Map
*/
public static Map> getProjectionsFor(Class> sourceType) {
Assert.notNull(sourceType, "目标类型不能为null");
Class> userType = ProxyUtils.getUserClass(sourceType);
Map byName = new HashMap();
Map> result = new HashMap>();
for (ProjectionDefinition entry : PROJECTION_DEFINITIONS) {
if (!entry.sourceType.isAssignableFrom(userType)) {
continue;
}
ProjectionDefinition existing = byName.get(entry.name);
if (existing == null || isSubTypeOf(entry.sourceType, existing.sourceType)) {
byName.put(entry.name, entry);
result.put(entry.name, entry.targetType);
}
}
return result;
}
private static boolean isSubTypeOf(Class> left, Class> right) {
return right.isAssignableFrom(left) && !left.equals(right);
}
/**
* 投影定义
*
* @author Oliver Gierke
*/
@Value
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
static final class ProjectionDefinition {
private final @NonNull Class> sourceType, targetType;
private final @NonNull String name;
/**
* Creates a new ProjectionDefinitionKey for the given source type and name;
*
* @param sourceType must not be {@literal null}.
* @param targetType must not be {@literal null}.
* @param name must not be {@literal null} or empty.
*/
static ProjectionUtils.ProjectionDefinition of(Class> sourceType, Class> targetType, String name) {
Assert.hasText(name, "Name must not be null or empty!");
return new ProjectionUtils.ProjectionDefinition(sourceType, targetType, name);
}
}
}