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.querydsl.core.alias.PropertyAccessInvocationHandler Maven / Gradle / Ivy
/*
* Copyright 2015, The Querydsl Team (http://www.querydsl.com/team)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.querydsl.core.alias;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.ParameterizedExpression;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.PathMetadata;
import com.querydsl.core.types.PathMetadataFactory;
import com.querydsl.core.util.BeanUtils;
import com.querydsl.core.util.ReflectionUtils;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperMethod;
import net.bytebuddy.implementation.bind.annotation.This;
import org.jetbrains.annotations.Nullable;
/**
* {@code PropertyAccessInvocationHandler} is the main InvocationHandler class for the Byte Buddy
* alias proxies
*
* @author tiwe
*/
public class PropertyAccessInvocationHandler {
private static final int RETURN_VALUE = 42;
private final Expression> hostExpression;
private final AliasFactory aliasFactory;
private final Map> propToExpr = new ConcurrentHashMap<>();
private final Map propToObj = new ConcurrentHashMap<>();
private final PathFactory pathFactory;
private final TypeSystem typeSystem;
PropertyAccessInvocationHandler(
Expression> host,
AliasFactory aliasFactory,
PathFactory pathFactory,
TypeSystem typeSystem) {
this.hostExpression = host;
this.aliasFactory = aliasFactory;
this.pathFactory = pathFactory;
this.typeSystem = typeSystem;
}
// CHECKSTYLE:OFF
@RuntimeType
public Object intercept(
@This Object proxy,
@Origin Method method,
@AllArguments Object[] args,
@SuperMethod(nullIfImpossible = true) Method methodProxy) {
// CHECKSTYLE:ON
Object rv = null;
MethodType methodType = MethodType.get(method);
if (methodType == MethodType.GETTER) {
var ptyName = propertyNameForGetter(method);
Class> ptyClass = method.getReturnType();
var genericType = method.getGenericReturnType();
if (propToObj.containsKey(ptyName)) {
rv = propToObj.get(ptyName);
} else {
var pm = createPropertyPath((Path>) hostExpression, ptyName);
rv = newInstance(ptyClass, genericType, proxy, ptyName, pm);
}
aliasFactory.setCurrent(propToExpr.get(ptyName));
} else if (methodType == MethodType.SCALA_GETTER) {
var ptyName = method.getName();
Class> ptyClass = method.getReturnType();
var genericType = method.getGenericReturnType();
if (propToObj.containsKey(ptyName)) {
rv = propToObj.get(ptyName);
} else {
var pm = createPropertyPath((Path>) hostExpression, ptyName);
rv = newInstance(ptyClass, genericType, proxy, ptyName, pm);
}
aliasFactory.setCurrent(propToExpr.get(ptyName));
} else if (methodType == MethodType.LIST_ACCESS || methodType == MethodType.SCALA_LIST_ACCESS) {
// TODO : manage cases where the argument is based on a property invocation
Object propKey = Arrays.asList(MethodType.LIST_ACCESS, args[0]);
if (propToObj.containsKey(propKey)) {
rv = propToObj.get(propKey);
} else {
var pm = createListAccessPath((Path>) hostExpression, (Integer) args[0]);
Class> elementType = ((ParameterizedExpression>) hostExpression).getParameter(0);
rv = newInstance(elementType, elementType, proxy, propKey, pm);
}
aliasFactory.setCurrent(propToExpr.get(propKey));
} else if (methodType == MethodType.LIST_GET_FIRST) {
// TODO : manage cases where the argument is based on a property invocation
Object propKey = Arrays.asList(MethodType.LIST_GET_FIRST);
if (propToObj.containsKey(propKey)) {
rv = propToObj.get(propKey);
} else {
var pm = PathMetadataFactory.forListFirst((Path>) hostExpression);
Class> elementType = ((ParameterizedExpression>) hostExpression).getParameter(0);
rv = newInstance(elementType, elementType, proxy, propKey, pm);
}
aliasFactory.setCurrent(propToExpr.get(propKey));
} else if (methodType == MethodType.MAP_ACCESS || methodType == MethodType.SCALA_MAP_ACCESS) {
Object propKey = Arrays.asList(MethodType.MAP_ACCESS, args[0]);
if (propToObj.containsKey(propKey)) {
rv = propToObj.get(propKey);
} else {
var pm = createMapAccessPath((Path>) hostExpression, args[0]);
Class> valueType = ((ParameterizedExpression>) hostExpression).getParameter(1);
rv = newInstance(valueType, valueType, proxy, propKey, pm);
}
aliasFactory.setCurrent(propToExpr.get(propKey));
} else if (methodType == MethodType.TO_STRING) {
rv = hostExpression.toString();
} else if (methodType == MethodType.HASH_CODE) {
rv = hostExpression.hashCode();
} else if (methodType == MethodType.GET_MAPPED_PATH) {
rv = hostExpression;
} else {
throw new IllegalArgumentException(
"Invocation of "
+ method.getName()
+ " with types "
+ Arrays.asList(method.getParameterTypes())
+ " not supported");
}
return rv;
}
@SuppressWarnings({"unchecked"})
@Nullable
protected T newInstance(
Class type, Type genericType, Object parent, Object propKey, PathMetadata metadata) {
Expression> path;
Object rv;
if (String.class.equals(type)) {
path = pathFactory.createStringPath(metadata);
// null is used as a return value to block method invocations on Strings
rv = null;
} else if (Integer.class.equals(type) || int.class.equals(type)) {
path = pathFactory.createNumberPath(Integer.class, metadata);
rv = RETURN_VALUE;
} else if (Byte.class.equals(type) || byte.class.equals(type)) {
path = pathFactory.createNumberPath(Byte.class, metadata);
rv = (byte) RETURN_VALUE;
} else if (java.util.Date.class.equals(type)) {
path = pathFactory.createDateTimePath((Class) type, metadata);
rv = new Date();
} else if (java.sql.Timestamp.class.equals(type)) {
path = pathFactory.createDateTimePath((Class) type, metadata);
rv = new Timestamp(System.currentTimeMillis());
} else if (java.sql.Date.class.equals(type)) {
path = pathFactory.createDatePath((Class) type, metadata);
rv = new java.sql.Date(System.currentTimeMillis());
} else if (java.sql.Time.class.equals(type)) {
path = pathFactory.createTimePath((Class) type, metadata);
rv = new java.sql.Time(System.currentTimeMillis());
} else if (Long.class.equals(type) || long.class.equals(type)) {
path = pathFactory.createNumberPath(Long.class, metadata);
rv = (long) RETURN_VALUE;
} else if (Short.class.equals(type) || short.class.equals(type)) {
path = pathFactory.createNumberPath(Short.class, metadata);
rv = (short) RETURN_VALUE;
} else if (Double.class.equals(type) || double.class.equals(type)) {
path = pathFactory.createNumberPath(Double.class, metadata);
rv = (double) RETURN_VALUE;
} else if (Float.class.equals(type) || float.class.equals(type)) {
path = pathFactory.createNumberPath(Float.class, metadata);
rv = (float) RETURN_VALUE;
} else if (BigInteger.class.equals(type)) {
path = pathFactory.createNumberPath((Class) type, metadata);
rv = BigInteger.valueOf(RETURN_VALUE);
} else if (BigDecimal.class.equals(type)) {
path = pathFactory.createNumberPath((Class) type, metadata);
rv = BigDecimal.valueOf(RETURN_VALUE);
} else if (Boolean.class.equals(type) || boolean.class.equals(type)) {
path = pathFactory.createBooleanPath(metadata);
rv = Boolean.TRUE;
} else if (typeSystem.isMapType(type)) {
Class keyType = (Class) ReflectionUtils.getTypeParameter(genericType, 0);
Class valueType = (Class) ReflectionUtils.getTypeParameter(genericType, 1);
path = pathFactory.createMapPath(keyType, valueType, metadata);
rv = aliasFactory.createAliasForProperty(type, path);
} else if (typeSystem.isListType(type)) {
Class elementType = (Class) ReflectionUtils.getTypeParameter(genericType, 0);
path = pathFactory.createListPath(elementType, metadata);
rv = aliasFactory.createAliasForProperty(type, path);
} else if (typeSystem.isSetType(type)) {
Class> elementType = ReflectionUtils.getTypeParameterAsClass(genericType, 0);
path = pathFactory.createSetPath(elementType, metadata);
rv = aliasFactory.createAliasForProperty(type, path);
} else if (typeSystem.isCollectionType(type)) {
Class> elementType = ReflectionUtils.getTypeParameterAsClass(genericType, 0);
path = pathFactory.createCollectionPath(elementType, metadata);
rv = aliasFactory.createAliasForProperty(type, path);
} else if (Enum.class.isAssignableFrom(type)) {
path = pathFactory.createEnumPath((Class) type, metadata);
rv = type.getEnumConstants()[0];
} else if (type.isArray()) {
path = pathFactory.createArrayPath((Class) type, metadata);
rv = Array.newInstance(type.getComponentType(), 5);
} else {
if (Number.class.isAssignableFrom(type)) {
path = pathFactory.createNumberPath((Class) type, metadata);
} else if (Comparable.class.isAssignableFrom(type)) {
path = pathFactory.createComparablePath((Class) type, metadata);
} else {
path = pathFactory.createEntityPath(type, metadata);
}
if (!Modifier.isFinal(type.getModifiers())) {
rv = aliasFactory.createAliasForProperty(type, path);
} else {
rv = null;
}
}
if (rv == null) {
propToObj.remove(propKey);
} else {
propToObj.put(propKey, rv);
}
propToExpr.put(propKey, path);
return (T) rv;
}
protected String propertyNameForGetter(Method method) {
var name = method.getName();
name = name.startsWith("is") ? name.substring(2) : name.substring(3);
return BeanUtils.uncapitalize(name);
}
protected PathMetadata createPropertyPath(Path> path, String propertyName) {
return PathMetadataFactory.forProperty(path, propertyName);
}
protected PathMetadata createListAccessPath(Path> path, Integer index) {
return PathMetadataFactory.forListAccess(path, index);
}
protected PathMetadata createMapAccessPath(Path> path, Object key) {
return PathMetadataFactory.forMapAccess(path, key);
}
}