/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.tree.select;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.hibernate.query.sqm.consume.spi.SemanticQueryWalker;
import org.hibernate.query.sqm.domain.SqmExpressableType;
import org.hibernate.query.sqm.domain.type.SqmDomainType;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.jboss.logging.Logger;
import static org.hibernate.query.sqm.tree.select.SqmDynamicInstantiationTarget.Nature.CLASS;
import static org.hibernate.query.sqm.tree.select.SqmDynamicInstantiationTarget.Nature.LIST;
import static org.hibernate.query.sqm.tree.select.SqmDynamicInstantiationTarget.Nature.MAP;
/**
* Represents a dynamic instantiation ({@code select new XYZ(...) ...}) as part of the SQM.
*
* @author Steve Ebersole
*/
public class SqmDynamicInstantiation
implements SqmExpression, SqmAliasedExpressionContainer<SqmDynamicInstantiationArgument> {
private static final Logger log = Logger.getLogger( SqmDynamicInstantiation.class );
public static SqmDynamicInstantiation forClassInstantiation(Class targetJavaType) {
return new SqmDynamicInstantiation(
new DynamicInstantiationTargetImpl( CLASS, targetJavaType )
);
}
public static SqmDynamicInstantiation forMapInstantiation() {
return new SqmDynamicInstantiation( new DynamicInstantiationTargetImpl( MAP, Map.class ) );
}
public static SqmDynamicInstantiation forListInstantiation() {
return new SqmDynamicInstantiation( new DynamicInstantiationTargetImpl( LIST, List.class ) );
}
private final SqmDynamicInstantiationTarget instantiationTarget;
private List<SqmDynamicInstantiationArgument> arguments;
private SqmDynamicInstantiation(SqmDynamicInstantiationTarget instantiationTarget) {
this.instantiationTarget = instantiationTarget;
}
@Override
public String asLoggableText() {
return "<new " + instantiationTarget.getJavaType().getName() + ">";
}
@Override
public SqmExpressableType getExpressionType() {
return null;
}
@Override
public SqmExpressableType getInferableType() {
return null;
}
public SqmDynamicInstantiationTarget getInstantiationTarget() {
return instantiationTarget;
}
public List<SqmDynamicInstantiationArgument> getArguments() {
return arguments;
}
public void addArgument(SqmDynamicInstantiationArgument argument) {
if ( instantiationTarget.getNature() == LIST ) {
// really should not have an alias...
if ( argument.getAlias() != null ) {
log.debugf(
"Argument [%s] for dynamic List instantiation declared an 'injection alias' [%s] " +
"but such aliases are ignored for dynamic List instantiations",
argument.getExpression().toString(),
argument.getAlias()
);
}
}
else if ( instantiationTarget.getNature() == MAP ) {
// must(?) have an alias...
log.warnf(
"Argument [%s] for dynamic Map instantiation did not declare an 'injection alias' [%s] " +
"but such aliases are needed for dynamic Map instantiations; " +
"will likely cause problems later translating sqm",
argument.getExpression().toString(),
argument.getAlias()
);
}
if ( arguments == null ) {
arguments = new ArrayList<>();
}
arguments.add( argument );
}
@Override
public SqmDynamicInstantiationArgument add(SqmExpression expression, String alias) {
SqmDynamicInstantiationArgument argument = new SqmDynamicInstantiationArgument( expression, alias );
addArgument( argument );
return argument;
}
@Override
public void add(SqmDynamicInstantiationArgument aliasExpression) {
addArgument( aliasExpression );
}
@Override
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitDynamicInstantiation( this );
}
public SqmDynamicInstantiation makeShallowCopy() {
return new SqmDynamicInstantiation( getInstantiationTarget() );
}
@Override
public SqmDomainType getExportedDomainType() {
return null;
}
private static class DynamicInstantiationTargetImpl implements SqmDynamicInstantiationTarget {
private final Nature nature;
private final Class javaType;;
public DynamicInstantiationTargetImpl(Nature nature, Class javaType) {
this.nature = nature;
this.javaType = javaType;
}
@Override
public Nature getNature() {
return nature;
}
@Override
public Class getJavaType() {
return javaType;
}
}
}