io.github.perplexhub.rsql.RSQLVisitorBase Maven / Gradle / Ivy
package io.github.perplexhub.rsql;
import java.lang.reflect.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.Map.Entry;
import javax.persistence.EntityManager;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.Attribute.PersistentAttributeType;
import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.PluralAttribute;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.util.StringUtils;
import cz.jirutka.rsql.parser.ast.RSQLVisitor;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@SuppressWarnings({ "rawtypes", "unchecked" })
public abstract class RSQLVisitorBase implements RSQLVisitor {
protected static volatile @Setter Map managedTypeMap;
protected static volatile @Setter Map entityManagerMap;
protected static final Map primitiveToWrapper;
protected static volatile @Setter Map, Map> propertyRemapping;
protected static volatile @Setter Map, List> globalPropertyWhitelist;
protected static volatile @Setter Map, List> globalPropertyBlacklist;
protected static volatile @Setter ConfigurableConversionService defaultConversionService;
protected @Setter Map, List> propertyWhitelist;
protected @Setter Map, List> propertyBlacklist;
protected Map getManagedTypeMap() {
return managedTypeMap != null ? managedTypeMap : Collections.emptyMap();
}
protected Map getEntityManagerMap() {
return entityManagerMap != null ? entityManagerMap : Collections.emptyMap();
}
protected abstract Map getPropertyPathMapper();
public Map, Map> getPropertyRemapping() {
return propertyRemapping != null ? propertyRemapping : Collections.emptyMap();
}
protected Object convert(String source, Class targetType) {
log.debug("convert(source:{},targetType:{})", source, targetType);
Object object = null;
try {
if (defaultConversionService.canConvert(String.class, targetType)) {
object = defaultConversionService.convert(source, targetType);
} else if (targetType.equals(String.class)) {
object = source;
} else if (targetType.equals(UUID.class)) {
object = UUID.fromString(source);
} else if (targetType.equals(Date.class) || targetType.equals(java.sql.Date.class)) {
object = java.sql.Date.valueOf(LocalDate.parse(source));
} else if (targetType.equals(LocalDate.class)) {
object = LocalDate.parse(source);
} else if (targetType.equals(LocalDateTime.class)) {
object = LocalDateTime.parse(source);
} else if (targetType.equals(OffsetDateTime.class)) {
object = OffsetDateTime.parse(source);
} else if (targetType.equals(ZonedDateTime.class)) {
object = ZonedDateTime.parse(source);
} else if (targetType.equals(Character.class)) {
object = (!StringUtils.isEmpty(source) ? source.charAt(0) : null);
} else if (targetType.equals(boolean.class) || targetType.equals(Boolean.class)) {
object = Boolean.valueOf(source);
} else if (targetType.isEnum()) {
object = Enum.valueOf(targetType, source);
} else {
Constructor> cons = (Constructor>) targetType.getConstructor(new Class>[] { String.class });
object = cons.newInstance(new Object[] { source });
}
return object;
} catch (DateTimeParseException | IllegalArgumentException e) {
log.debug("Parsing [{}] with [{}] causing [{}], skip", source, targetType.getName(), e.getMessage());
} catch (Exception e) {
log.error("Parsing [{}] with [{}] causing [{}], add your parser via RSQLSupport.addConverter(Type.class, Type::valueOf)", source, targetType.getName(), e.getMessage(), e);
}
return null;
}
protected void accessControl(Class type, String name) {
log.debug("accessControl(type:{},name:{})", type, name);
if (propertyWhitelist != null && propertyWhitelist.containsKey(type)) {
if (!propertyWhitelist.get(type).contains(name)) {
String msg = "Property " + type.getName() + "." + name + " is not on whitelist";
log.debug(msg);
throw new PropertyNotWhitelistedException(name, type, msg);
}
} else if (globalPropertyWhitelist != null && globalPropertyWhitelist.containsKey(type)) {
if (!globalPropertyWhitelist.get(type).contains(name)) {
String msg = "Property " + type.getName() + "." + name + " is not on global whitelist";
log.debug(msg);
throw new PropertyNotWhitelistedException(name, type, msg);
}
}
if (propertyBlacklist != null && propertyBlacklist.containsKey(type)) {
if (propertyBlacklist.get(type).contains(name)) {
String msg = "Property " + type.getName() + "." + name + " is on blacklist";
log.debug(msg);
throw new PropertyBlacklistedException(name, type, msg);
}
} else if (globalPropertyBlacklist != null && globalPropertyBlacklist.containsKey(type)) {
if (globalPropertyBlacklist.get(type).contains(name)) {
String msg = "Property " + type.getName() + "." + name + " is on global blacklist";
log.debug(msg);
throw new PropertyBlacklistedException(name, type, msg);
}
}
}
protected String mapPropertyPath(String propertyPath) {
if (!getPropertyPathMapper().isEmpty()) {
String property = getPropertyPathMapper().get(propertyPath);
if (StringUtils.hasText(property)) {
log.debug("Map propertyPath [{}] to [{}]", propertyPath, property);
return property;
}
}
return propertyPath;
}
protected String mapProperty(String selector, Class> entityClass) {
if (!getPropertyRemapping().isEmpty()) {
Map map = getPropertyRemapping().get(entityClass);
String property = (map != null) ? map.get(selector) : null;
if (StringUtils.hasText(property)) {
log.debug("Map property [{}] to [{}] for [{}]", selector, property, entityClass);
return property;
}
}
return selector;
}
protected Class> findPropertyType(String property, ManagedType classMetadata) {
Class> propertyType = null;
if (classMetadata.getAttribute(property).isCollection()) {
propertyType = ((PluralAttribute) classMetadata.getAttribute(property)).getBindableJavaType();
} else {
propertyType = classMetadata.getAttribute(property).getJavaType();
}
return propertyType;
}
@SneakyThrows(Exception.class)
protected ManagedType getManagedType(Class cls) {
Exception ex = null;
if (getEntityManagerMap().size() > 0) {
ManagedType managedType = getManagedTypeMap().get(cls);
if (managedType != null) {
log.debug("Found managed type [{}] in cache", cls);
return managedType;
}
for (Entry entityManagerEntry : getEntityManagerMap().entrySet()) {
try {
managedType = entityManagerEntry.getValue().getMetamodel().managedType(cls);
getManagedTypeMap().put(cls, managedType);
log.debug("Found managed type [{}] in EntityManager [{}]", cls, entityManagerEntry.getKey());
return managedType;
} catch (Exception e) {
if (e != null) {
ex = e;
}
log.debug("[{}] not found in EntityManager [{}] due to [{}]", cls, entityManagerEntry.getKey(), e == null ? "-" : e.getMessage());
}
}
}
log.error("[{}] not found in EntityManager{}: [{}]", cls, getEntityManagerMap().size() > 1 ? "s" : "", StringUtils.collectionToCommaDelimitedString(getEntityManagerMap().keySet()));
throw ex != null ? ex : new IllegalStateException("No entity manager bean found in application context");
}
protected ManagedType getManagedElementCollectionType(String mappedProperty, ManagedType classMetadata) {
try {
Class> cls = findPropertyType(mappedProperty, classMetadata);
if (!cls.isPrimitive() && !primitiveToWrapper.containsValue(cls) && !cls.equals(String.class) && getEntityManagerMap().size() > 0) {
ManagedType managedType = getManagedTypeMap().get(cls);
if (managedType != null) {
log.debug("Found managed type [{}] in cache", cls);
return managedType;
}
for (Entry entityManagerEntry : getEntityManagerMap().entrySet()) {
managedType = (ManagedType) entityManagerEntry.getValue().getMetamodel().managedType(cls);
getManagedTypeMap().put(cls, managedType);
log.info("Found managed type [{}] in EntityManager [{}]", cls, entityManagerEntry.getKey());
return managedType;
}
}
} catch (Exception e) {
log.warn("Unable to get the managed type of [{}]", mappedProperty, e);
}
return classMetadata;
}
protected boolean hasPropertyName(String property, ManagedType classMetadata) {
try {
return classMetadata.getAttribute(property) != null;
} catch (IllegalArgumentException e) {
return false;
}
}
@SneakyThrows
protected Class getElementCollectionGenericType(Class type, Attribute attribute) {
Member member = attribute.getJavaMember();
if (member instanceof Field) {
Field field = (Field) member;
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType rawType = (ParameterizedType) genericType;
Class elementCollectionClass = Class.forName(rawType.getActualTypeArguments()[0].getTypeName());
log.info("Map element collection generic type [{}] to [{}]", attribute.getName(), elementCollectionClass);
return elementCollectionClass;
}
}
return type;
}
protected boolean isEmbeddedType(String property, ManagedType classMetadata) {
return classMetadata.getAttribute(property).getPersistentAttributeType() == PersistentAttributeType.EMBEDDED;
}
protected boolean isElementCollectionType(String property, ManagedType classMetadata) {
return classMetadata.getAttribute(property).getPersistentAttributeType() == PersistentAttributeType.ELEMENT_COLLECTION;
}
protected boolean isAssociationType(String property, ManagedType classMetadata) {
return classMetadata.getAttribute(property).isAssociation();
}
protected boolean isOneToOneAssociationType(String property, ManagedType classMetadata) {
return classMetadata.getAttribute(property).isAssociation()
&& PersistentAttributeType.ONE_TO_ONE == classMetadata.getAttribute(property).getPersistentAttributeType();
}
protected boolean isOneToManyAssociationType(String property, ManagedType classMetadata) {
return classMetadata.getAttribute(property).isAssociation()
&& PersistentAttributeType.ONE_TO_MANY == classMetadata.getAttribute(property).getPersistentAttributeType();
}
static {
Map map = new HashMap<>();
map.put(boolean.class, Boolean.class);
map.put(byte.class, Byte.class);
map.put(char.class, Character.class);
map.put(double.class, Double.class);
map.put(float.class, Float.class);
map.put(int.class, Integer.class);
map.put(long.class, Long.class);
map.put(short.class, Short.class);
map.put(void.class, Void.class);
primitiveToWrapper = Collections.unmodifiableMap(map);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy