Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.leeonky.map.PermitMapper Maven / Gradle / Ivy
package com.github.leeonky.map;
import com.github.leeonky.util.BeanClass;
import com.github.leeonky.util.Converter;
import com.github.leeonky.util.GenericType;
import com.github.leeonky.util.PropertyWriter;
import org.reflections.Reflections;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class PermitMapper {
private static final Class>[] VOID_SCOPES = {void.class};
private Class> scope = void.class;
private Converter converter = Converter.createDefault();
private PermitRegisterConfig permitRegisterConfig = new PermitRegisterConfig();
public PermitMapper(String... packages) {
new Reflections((Object[]) packages)
.getTypesAnnotatedWith(Permit.class)
.forEach(this::register);
}
private void register(Class> type) {
permitRegisterConfig.register(type.getAnnotation(Permit.class).action(),
type.getAnnotation(Permit.class).target(), getScopes(type), type);
PolymorphicPermitIdentityString identityString = type.getAnnotation(PolymorphicPermitIdentityString.class);
if (identityString != null)
permitRegisterConfig.registerPolymorphic(type.getAnnotation(Permit.class).action(),
getScopes(type), identityString.value(), type);
}
private Class>[] getScopes(Class> type) {
Class>[] scopes = type.getAnnotation(PermitScope.class) == null ?
type.getAnnotation(Permit.class).scope()
: type.getAnnotation(PermitScope.class).value();
return scopes.length == 0 ? VOID_SCOPES : scopes;
}
@SuppressWarnings("unchecked")
public T permit(T object, Class> target, Class> action) {
return (T) findPermit(target, action).map(p -> {
if (object instanceof Map)
return permitMap((Map) object, p);
else if (object instanceof List)
return permitList((List>) object, p);
else
throw new IllegalArgumentException("Not support type " + object.getClass().getName() + ", only support Map or List");
}).orElse(object);
}
@SuppressWarnings("unchecked")
private List> permitList(List> list, Class> permit) {
return list.stream().map(m -> permitMap((Map) m, permit)).collect(Collectors.toList());
}
private Map permitMap(Map map, Class> permit) {
return collectPermittedProperties(map, permit)
.reduce(new LinkedHashMap<>(), (result, property) -> assignToResult(result, property,
permitPropertyObjectValue(map.get(property.getName()), property.getGenericType(), permit, property)),
Mapper::NotSupportParallelStreamReduce);
}
private Stream extends PropertyWriter>> collectPermittedProperties(Map map, Class> permit) {
return BeanClass.create(permit).getPropertyWriters().values().stream()
.filter(property -> map.containsKey(property.getName()));
}
private LinkedHashMap assignToResult(LinkedHashMap result, PropertyWriter> property, Object value) {
ToProperty toProperty = property.getAnnotation(ToProperty.class);
if (toProperty != null)
assignToNestedMap(result, value, toProperty.value().split("\\."));
else
result.put(property.getName(), value);
return result;
}
@SuppressWarnings("unchecked")
private void assignToNestedMap(LinkedHashMap result, Object value, String[] propertyChain) {
Arrays.stream(propertyChain, 0, propertyChain.length - 1)
.reduce(result, (m, p) -> (LinkedHashMap) m.computeIfAbsent(p, k -> new LinkedHashMap<>()),
Mapper::NotSupportParallelStreamReduce)
.put(propertyChain[propertyChain.length - 1], value);
}
public Optional> findPermit(Class> target, Class> action) {
return permitRegisterConfig.findPermit(target, action, scope);
}
public void setScope(Class> scope) {
this.scope = scope;
}
@SuppressWarnings("unchecked")
private Object permitPropertyObjectValue(Object value, GenericType genericType, Class> containingPermit, PropertyWriter> property) {
Class> permit = genericType.getRawType();
if (value instanceof Map) {
return processPolymorphicAndPermitMap((Map) value, permit, containingPermit, property);
} else if (value instanceof Iterable) {
return processPolymorphicAndPermitList((Iterable>) value, genericType, containingPermit, property);
} else
return converter.tryConvert(permit, value);
}
private Object processPolymorphicAndPermitList(Iterable> value, GenericType genericType, Class> containingPermit, PropertyWriter> property) {
GenericType subGenericType = genericType.getGenericTypeParameter(0)
.orElseThrow(() -> new IllegalStateException(String.format("Should specify element type in '%s::%s'", containingPermit.getName(), property.getName())));
return StreamSupport.stream(value.spliterator(), false)
.map(e -> permitPropertyObjectValue(e, subGenericType, containingPermit, property))
.collect(Collectors.toList());
}
private Object processPolymorphicAndPermitMap(Map value, Class> permit, Class> containingPermit, PropertyWriter> property) {
PermitAction action = property.getAnnotation(PermitAction.class);
if (action != null) {
PolymorphicPermitIdentity polymorphicPermitIdentity = permit.getAnnotation(PolymorphicPermitIdentity.class);
if (polymorphicPermitIdentity == null)
throw new IllegalStateException("Should specify property name via @PolymorphicPermitIdentity in '" + permit.getName() + "'");
return permitMap(value, permitRegisterConfig.findPolymorphicPermit(permit, action.value(), scope, value.get(polymorphicPermitIdentity.value()))
.orElseThrow(() -> new IllegalStateException(String.format("Cannot find permit for %s[%s] in '%s::%s'",
polymorphicPermitIdentity.value(), value.get(polymorphicPermitIdentity.value()), containingPermit.getName(), property.getName()))));
}
return permitMap(value, permit);
}
}