/* * 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() { } }