org.mvel2.ast.NewObjectNode Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of virtdata-lib-realer Show documentation
Show all versions of virtdata-lib-realer Show documentation
With inspiration from other libraries
/**
* MVEL 2.0
* Copyright (C) 2007 The Codehaus
* Mike Brock, Dhanji Prasanna, John Graham, Mark Proctor
*
* 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 org.mvel2.ast;
import org.mvel2.CompileException;
import org.mvel2.ErrorDetail;
import org.mvel2.ParserContext;
import org.mvel2.PropertyAccessor;
import org.mvel2.compiler.Accessor;
import org.mvel2.compiler.ExecutableStatement;
import org.mvel2.compiler.PropertyVerifier;
import org.mvel2.integration.VariableResolverFactory;
import org.mvel2.optimizers.AccessorOptimizer;
import org.mvel2.optimizers.OptimizerFactory;
import org.mvel2.util.ArrayTools;
import org.mvel2.util.ErrorUtil;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.List;
import static java.lang.reflect.Array.newInstance;
import static org.mvel2.DataConversion.convert;
import static org.mvel2.MVEL.analyze;
import static org.mvel2.MVEL.eval;
import static org.mvel2.optimizers.OptimizerFactory.getThreadAccessorOptimizer;
import static org.mvel2.util.ArrayTools.findFirst;
import static org.mvel2.util.CompilerTools.getInjectedImports;
import static org.mvel2.util.ParseTools.*;
import static org.mvel2.util.ReflectionUtil.toPrimitiveArrayType;
/**
* @author Christopher Brock
*/
@SuppressWarnings({"ManualArrayCopy"})
public class NewObjectNode extends ASTNode {
private transient Accessor newObjectOptimizer;
private TypeDescriptor typeDescr;
private char[] name;
private static final Class[] EMPTYCLS = new Class[0];
public NewObjectNode(TypeDescriptor typeDescr, int fields, ParserContext pCtx) {
super(pCtx);
this.typeDescr = typeDescr;
this.fields = fields;
this.expr = typeDescr.getExpr();
this.start = typeDescr.getStart();
this.offset = typeDescr.getOffset();
if (offset < expr.length) {
this.name = subArray(expr, start, start + offset);
}
else {
this.name = expr;
}
if ((fields & COMPILE_IMMEDIATE) != 0) {
if (pCtx != null && pCtx.hasImport(typeDescr.getClassName())) {
pCtx.setAllowBootstrapBypass(false);
egressType = pCtx.getImport(typeDescr.getClassName());
}
else {
try {
egressType = Class.forName(typeDescr.getClassName(), true, getClassLoader());
}
catch (ClassNotFoundException e) {
if (pCtx.isStrongTyping())
pCtx.addError(new ErrorDetail(expr, start, true, "could not resolve class: " + typeDescr.getClassName()));
return;
// do nothing.
}
}
if (egressType != null) {
rewriteClassReferenceToFQCN(fields);
if (typeDescr.isArray()) {
try {
egressType = egressType.isPrimitive() ?
toPrimitiveArrayType(egressType) :
findClass(null, repeatChar('[', typeDescr.getArrayLength()) + "L" + egressType.getName() + ";", pCtx);
}
catch (Exception e) {
e.printStackTrace();
// for now, don't handle this.
}
}
}
if (pCtx != null) {
if (egressType == null) {
pCtx.addError(new ErrorDetail(expr, start, true, "could not resolve class: " + typeDescr.getClassName()));
return;
}
if (!typeDescr.isArray()) {
String[] cnsResid = captureContructorAndResidual(expr, start, offset);
final List constructorParms
= parseMethodOrConstructor(cnsResid[0].toCharArray());
final Class[] parms = new Class[constructorParms.size()];
for (int i = 0; i < parms.length; i++) {
parms[i] = analyze(constructorParms.get(i), pCtx);
}
if (getBestConstructorCandidate(parms, egressType, true) == null) {
if (pCtx.isStrongTyping())
pCtx.addError(new ErrorDetail(expr, start, pCtx.isStrongTyping(), "could not resolve constructor " + typeDescr.getClassName()
+ Arrays.toString(parms)));
}
if (cnsResid.length == 2) {
String residualProperty =
cnsResid[1].trim();
if (residualProperty.length() == 0) return;
this.egressType = new PropertyVerifier(residualProperty, pCtx, egressType).analyze();
}
}
}
}
}
private void rewriteClassReferenceToFQCN(int fields) {
String FQCN = egressType.getName();
if (typeDescr.getClassName().indexOf('.') == -1) {
int idx = ArrayTools.findFirst('(', 0, name.length, name);
char[] fqcn = FQCN.toCharArray();
if (idx == -1) {
this.name = new char[idx = fqcn.length];
for (int i = 0; i < idx; i++)
this.name[i] = fqcn[i];
}
else {
char[] newName = new char[fqcn.length + (name.length - idx)];
for (int i = 0; i < fqcn.length; i++)
newName[i] = fqcn[i];
int i0 = name.length - idx;
int i1 = fqcn.length;
for (int i = 0; i < i0; i++)
newName[i + i1] = name[i + idx];
this.name = newName;
}
this.typeDescr.updateClassName(name, 0, name.length, fields);
}
}
public Object getReducedValueAccelerated(Object ctx, Object thisValue, VariableResolverFactory factory) {
if (newObjectOptimizer == null) {
if (egressType == null) {
/**
* This means we couldn't resolve the type at the time this AST node was created, which means
* we have to attempt runtime resolution.
*/
if (factory != null && factory.isResolveable(typeDescr.getClassName())) {
try {
egressType = (Class) factory.getVariableResolver(typeDescr.getClassName()).getValue();
rewriteClassReferenceToFQCN(COMPILE_IMMEDIATE);
if (typeDescr.isArray()) {
try {
egressType = findClass(factory,
repeatChar('[', typeDescr.getArrayLength()) + "L" + egressType.getName() + ";", pCtx);
}
catch (Exception e) {
// for now, don't handle this.
}
}
}
catch (ClassCastException e) {
throw new CompileException("cannot construct object: " + typeDescr.getClassName()
+ " is not a class reference", expr, start, e);
}
}
}
if (typeDescr.isArray()) {
return (newObjectOptimizer = new NewObjectArray(getBaseComponentType(egressType.getComponentType()), typeDescr.getCompiledArraySize()))
.getValue(ctx, thisValue, factory);
}
try {
AccessorOptimizer optimizer = getThreadAccessorOptimizer();
ParserContext pCtx = this.pCtx;
if (pCtx == null) {
pCtx = new ParserContext();
pCtx.getParserConfiguration().setAllImports(getInjectedImports(factory));
}
newObjectOptimizer = optimizer.optimizeObjectCreation(pCtx, name, 0, name.length, ctx, thisValue, factory);
/**
* Check to see if the optimizer actually produced the object during optimization. If so,
* we return that value now.
*/
if (optimizer.getResultOptPass() != null) {
egressType = optimizer.getEgressType();
return optimizer.getResultOptPass();
}
}
catch (CompileException e) {
throw ErrorUtil.rewriteIfNeeded(e, expr, start);
}
finally {
OptimizerFactory.clearThreadAccessorOptimizer();
}
}
return newObjectOptimizer.getValue(ctx, thisValue, factory);
}
public Object getReducedValue(Object ctx, Object thisValue, VariableResolverFactory factory) {
try {
if (typeDescr.isArray()) {
Class cls = findClass(factory, typeDescr.getClassName(), pCtx);
int[] s = new int[typeDescr.getArrayLength()];
ArraySize[] arraySize = typeDescr.getArraySize();
for (int i = 0; i < s.length; i++) {
s[i] = convert(eval(arraySize[i].value, ctx, factory), Integer.class);
}
return newInstance(cls, s);
}
else {
String[] cnsRes = captureContructorAndResidual(name, 0, name.length);
List constructorParms = parseMethodOrConstructor(cnsRes[0].toCharArray());
if (constructorParms != null) {
Class cls = findClass(factory, new String(subset(name, 0, findFirst('(', 0, name.length, name))).trim(), pCtx);
Object[] parms = new Object[constructorParms.size()];
for (int i = 0; i < constructorParms.size(); i++) {
parms[i] = eval(constructorParms.get(i), ctx, factory);
}
Constructor cns = getBestConstructorCandidate(parms, cls, false);
if (cns == null)
throw new CompileException("unable to find constructor for: " + cls.getName(), expr, start);
for (int i = 0; i < parms.length; i++) {
//noinspection unchecked
parms[i] = convert(parms[i], cns.getParameterTypes()[i]);
}
if (cnsRes.length > 1) {
return PropertyAccessor.get(cnsRes[1], cns.newInstance(parms), factory, thisValue, pCtx);
}
else {
return cns.newInstance(parms);
}
}
else {
Constructor> cns = Class.forName(typeDescr.getClassName(), true, pCtx.getParserConfiguration().getClassLoader())
.getConstructor(EMPTYCLS);
if (cnsRes.length > 1) {
return PropertyAccessor.get(cnsRes[1], cns.newInstance(), factory, thisValue, pCtx);
}
else {
return cns.newInstance();
}
}
}
}
catch (CompileException e) {
throw e;
}
catch (ClassNotFoundException e) {
throw new CompileException("unable to resolve class: " + e.getMessage(), expr, start, e);
}
catch (NoSuchMethodException e) {
throw new CompileException("cannot resolve constructor: " + e.getMessage(), expr, start, e);
}
catch (Exception e) {
throw new CompileException("could not instantiate class: " + e.getMessage(), expr, start, e);
}
}
private boolean isPrototypeFunction() {
return pCtx.getFunctions().containsKey(typeDescr.getClassName());
}
private Object createPrototypalObject(Object ctx, Object thisRef, VariableResolverFactory factory) {
final Function function = pCtx.getFunction(typeDescr.getClassName());
return function.getReducedValueAccelerated(ctx, thisRef, factory);
}
public static class NewObjectArray implements Accessor, Serializable {
private ExecutableStatement[] sizes;
private Class arrayType;
public NewObjectArray(Class arrayType, ExecutableStatement[] sizes) {
this.arrayType = arrayType;
this.sizes = sizes;
}
public Object getValue(Object ctx, Object elCtx, VariableResolverFactory variableFactory) {
int[] s = new int[sizes.length];
for (int i = 0; i < s.length; i++) {
s[i] = convert(sizes[i].getValue(ctx, elCtx, variableFactory), Integer.class);
}
return newInstance(arrayType, s);
}
public Object setValue(Object ctx, Object elCtx, VariableResolverFactory variableFactory, Object value) {
return null;
}
public Class getKnownEgressType() {
try {
return Class.forName("[L" + arrayType.getName() + ";");
}
catch (ClassNotFoundException cne) {
return null;
}
}
}
public TypeDescriptor getTypeDescr() {
return typeDescr;
}
public Accessor getNewObjectOptimizer() {
return newObjectOptimizer;
}
}