/*
* 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.types;
import java.util.ArrayList;
import java.util.List;
import com.querydsl.core.util.ArrayUtils;
/**
* Utility class to expand {@link FactoryExpression} constructor arguments and compress {@link FactoryExpression}
* invocation arguments
*
* @author tiwe
*
*/
public final class FactoryExpressionUtils {
/**
* {@code FactoryExpressionAdapter} provides an adapter implementation of the {@link FactoryExpression} interface
*
* @param <T>
*/
public static class FactoryExpressionAdapter<T> extends ExpressionBase<T> implements FactoryExpression<T> {
private static final long serialVersionUID = -2742333128230913512L;
private final FactoryExpression<T> inner;
private final List<Expression<?>> args;
FactoryExpressionAdapter(FactoryExpression<T> inner) {
super(inner.getType());
this.inner = inner;
this.args = expand(inner.getArgs());
}
FactoryExpressionAdapter(FactoryExpression<T> inner, List<Expression<?>> args) {
super(inner.getType());
this.inner = inner;
this.args = expand(args);
}
@Override
public List<Expression<?>> getArgs() {
return args;
}
@Override
public T newInstance(Object... a) {
return inner.newInstance(compress(inner.getArgs(), a));
}
@Override
public <R, C> R accept(Visitor<R, C> v, C context) {
return v.visit(this, context);
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o instanceof FactoryExpression) {
FactoryExpression<?> e = (FactoryExpression<?>) o;
return args.equals(e.getArgs()) && getType().equals(e.getType());
} else {
return false;
}
}
}
public static FactoryExpression<?> wrap(List<? extends Expression<?>> projection) {
boolean usesFactoryExpressions = false;
for (Expression<?> e : projection) {
usesFactoryExpressions |= e instanceof FactoryExpression;
}
if (usesFactoryExpressions) {
return wrap(new ArrayConstructorExpression<Object>(
projection.toArray(new Expression<?>[projection.size()])));
} else {
return null;
}
}
public static <T> FactoryExpression<T> wrap(FactoryExpression<T> expr, List<Expression<?>> conversions) {
return new FactoryExpressionAdapter<T>(expr, conversions);
}
public static <T> FactoryExpression<T> wrap(FactoryExpression<T> expr) {
for (Expression<?> arg : expr.getArgs()) {
if (arg instanceof ProjectionRole) {
arg = ((ProjectionRole) arg).getProjection();
}
if (arg instanceof FactoryExpression<?>) {
return new FactoryExpressionAdapter<T>(expr);
}
}
return expr;
}
private static List<Expression<?>> expand(List<Expression<?>> exprs) {
List<Expression<?>> rv = new ArrayList<Expression<?>>(exprs.size());
for (Expression<?> expr : exprs) {
if (expr instanceof ProjectionRole) {
expr = ((ProjectionRole) expr).getProjection();
}
if (expr instanceof FactoryExpression<?>) {
rv.addAll(expand(((FactoryExpression<?>) expr).getArgs()));
} else {
rv.add(expr);
}
}
return rv;
}
private static int countArguments(FactoryExpression<?> expr) {
int counter = 0;
for (Expression<?> arg : expr.getArgs()) {
if (arg instanceof ProjectionRole) {
arg = ((ProjectionRole) arg).getProjection();
}
if (arg instanceof FactoryExpression<?>) {
counter += countArguments((FactoryExpression<?>) arg);
} else {
counter++;
}
}
return counter;
}
private static Object[] compress(List<Expression<?>> exprs, Object[] args) {
Object[] rv = new Object[exprs.size()];
int offset = 0;
for (int i = 0; i < exprs.size(); i++) {
Expression<?> expr = exprs.get(i);
if (expr instanceof ProjectionRole) {
expr = ((ProjectionRole) expr).getProjection();
}
if (expr instanceof FactoryExpression<?>) {
FactoryExpression<?> fe = (FactoryExpression<?>) expr;
int fullArgsLength = countArguments(fe);
Object[] compressed = compress(fe.getArgs(), ArrayUtils.subarray(args, offset, offset + fullArgsLength));
rv[i] = fe.newInstance(compressed);
offset += fullArgsLength;
} else {
rv[i] = args[offset];
offset++;
}
}
return rv;
}
private FactoryExpressionUtils() { }
}