org.apache.ibatis.ognl.ASTProperty Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.servicemix.bundles.mybatis
Show all versions of org.apache.servicemix.bundles.mybatis
This OSGi bundle wraps ${pkgArtifactId} ${pkgVersion} jar file.
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.ibatis.ognl;
import org.apache.ibatis.ognl.enhance.ExpressionCompiler;
import org.apache.ibatis.ognl.enhance.UnsupportedCompilationException;
import java.beans.IndexedPropertyDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Iterator;
public class ASTProperty extends SimpleNode implements NodeType {
private static final long serialVersionUID = -7755110504199540734L;
private boolean indexedAccess = false;
private Class> getterClass;
private Class> setterClass;
public ASTProperty(int id) {
super(id);
}
public void setIndexedAccess(boolean value) {
indexedAccess = value;
}
/**
* Returns true if this property is itself an index reference.
*
* @return true if this property is an index reference, false otherwise.
*/
public boolean isIndexedAccess() {
return indexedAccess;
}
/**
* Returns true if this property is described by an IndexedPropertyDescriptor and that if
* followed by an index specifier it will call the index get/set methods rather than go through
* property accessors.
*
* @param context the OgnlContext within which to perform the operation.
* @param source the Object (indexed property) from which to retrieve the indexed property type.
* @return the int representing the indexed property type of source.
* @throws OgnlException if source is not an indexed property.
*/
public int getIndexedPropertyType(OgnlContext context, Object source)
throws OgnlException {
Class> type = context.getCurrentType();
Class> prevType = context.getPreviousType();
try {
if (!isIndexedAccess()) {
Object property = getProperty(context, source);
if (property instanceof String) {
return OgnlRuntime.getIndexedPropertyType((source == null)
? null
: OgnlRuntime.getCompiler().getInterfaceClass(source.getClass()), (String) property);
}
}
return OgnlRuntime.INDEXED_PROPERTY_NONE;
} finally {
context.setCurrentObject(source);
context.setCurrentType(type);
context.setPreviousType(prevType);
}
}
public Object getProperty(OgnlContext context, Object source) throws OgnlException {
return children[0].getValue(context, context.getRoot());
}
protected Object getValueBody(OgnlContext context, Object source)
throws OgnlException {
Object property = getProperty(context, source);
Object result = OgnlRuntime.getProperty(context, source, property);
if (result == null) {
result = OgnlRuntime.getNullHandler(OgnlRuntime.getTargetClass(source)).nullPropertyValue(context, source, property);
}
return result;
}
protected void setValueBody(OgnlContext context, Object target, Object value)
throws OgnlException {
OgnlRuntime.setProperty(context, target, getProperty(context, target), value);
}
public boolean isNodeSimpleProperty(OgnlContext context)
throws OgnlException {
return (children != null) && (children.length == 1) && ((SimpleNode) children[0]).isConstant(context);
}
public Class> getGetterClass() {
return getterClass;
}
public Class> getSetterClass() {
return setterClass;
}
public String toString() {
String result;
if (isIndexedAccess()) {
result = "[" + children[0] + "]";
} else {
result = ((ASTConst) children[0]).getValue().toString();
}
return result;
}
public String toGetSourceString(OgnlContext context, Object target) {
if (context.getCurrentObject() == null)
throw new UnsupportedCompilationException("Current target is null.");
String result = "";
Method m = null;
try {
/* System.out.println("astproperty is indexed? : " + isIndexedAccess() + " child: " + _children[0].getClass().getName()
+ " target: " + target.getClass().getName() + " current object: " + context.getCurrentObject().getClass().getName());*/
if (isIndexedAccess()) {
Object value = children[0].getValue(context, context.getRoot());
if (value == null || DynamicSubscript.class.isAssignableFrom(value.getClass()))
throw new UnsupportedCompilationException("Value passed as indexed property was null or not supported.");
// Get root cast string if the child is a type that needs it (like a nested ASTProperty)
String srcString = children[0].toGetSourceString(context, context.getRoot());
srcString = ExpressionCompiler.getRootExpression(children[0], context.getRoot(), context) + srcString;
if (children[0] instanceof ASTChain) {
String cast = (String) context.remove(ExpressionCompiler.PRE_CAST);
if (cast != null)
srcString = cast + srcString;
}
if (children[0] instanceof ASTConst && context.getCurrentObject() instanceof String)
srcString = "\"" + srcString + "\"";
// System.out.println("indexed getting with child srcString: " + srcString + " value class: " + value.getClass() + " and child: " + _children[0].getClass());
if (context.get("_indexedMethod") != null) {
m = (Method) context.remove("_indexedMethod");
getterClass = m.getReturnType();
Object indexedValue = OgnlRuntime.callMethod(context, target, m.getName(), new Object[]{value});
context.setCurrentType(getterClass);
context.setCurrentObject(indexedValue);
context.setCurrentAccessor(OgnlRuntime.getCompiler().getSuperOrInterfaceClass(m, m.getDeclaringClass()));
return "." + m.getName() + "(" + srcString + ")";
} else {
PropertyAccessor p = OgnlRuntime.getPropertyAccessor(target.getClass());
// System.out.println("child value : " + _children[0].getValue(context, context.getCurrentObject()) + " using propaccessor " + p.getClass().getName()
// + " and srcString " + srcString + " on target: " + target);
Object currObj = context.getCurrentObject();
Class> currType = context.getCurrentType();
Class> prevType = context.getPreviousType();
Object indexVal = p.getProperty(context, target, value);
// reset current object for accessor
context.setCurrentObject(currObj);
context.setCurrentType(currType);
context.setPreviousType(prevType);
if (children[0] instanceof ASTConst && context.getCurrentObject() instanceof Number)
context.setCurrentType(OgnlRuntime.getPrimitiveWrapperClass(context.getCurrentObject().getClass()));
result = p.getSourceAccessor(context, target, srcString);
getterClass = context.getCurrentType();
context.setCurrentObject(indexVal);
return result;
}
}
String name = ((ASTConst) children[0]).getValue().toString();
if (!Iterator.class.isAssignableFrom(context.getCurrentObject().getClass())
|| (Iterator.class.isAssignableFrom(context.getCurrentObject().getClass()) && !name.contains("next"))) {
Object currObj = target;
try {
target = getValue(context, context.getCurrentObject());
} catch (NoSuchPropertyException e) {
try {
target = getValue(context, context.getRoot());
} catch (NoSuchPropertyException ex) {
// ignore
}
} finally {
context.setCurrentObject(currObj);
}
}
PropertyDescriptor pd = OgnlRuntime.getPropertyDescriptor(context.getCurrentObject().getClass(), name);
if (pd != null && pd.getReadMethod() != null
&& !context.getMemberAccess().isAccessible(context, context.getCurrentObject(), pd.getReadMethod(), name)) {
throw new UnsupportedCompilationException("Member access forbidden for property " + name + " on class " + context.getCurrentObject().getClass());
}
if (this.getIndexedPropertyType(context, context.getCurrentObject()) > 0 && pd != null) {
// if an indexed method accessor need to use special property descriptors to find methods
if (pd instanceof IndexedPropertyDescriptor) {
m = ((IndexedPropertyDescriptor) pd).getIndexedReadMethod();
} else {
if (pd instanceof ObjectIndexedPropertyDescriptor)
m = ((ObjectIndexedPropertyDescriptor) pd).getIndexedReadMethod();
else
throw new OgnlException("property '" + name + "' is not an indexed property");
}
if (parent == null) {
// the above pd will be the wrong result sometimes, such as methods like getValue(int) vs String[] getValue()
m = OgnlRuntime.getReadMethod(context.getCurrentObject().getClass(), name);
result = m.getName() + "()";
getterClass = m.getReturnType();
} else {
context.put("_indexedMethod", m);
}
} else {
/* System.out.println("astproperty trying to get " + name + " on object target: " + context.getCurrentObject().getClass().getName()
+ " current type " + context.getCurrentType() + " current accessor " + context.getCurrentAccessor()
+ " prev type " + context.getPreviousType() + " prev accessor " + context.getPreviousAccessor());*/
PropertyAccessor pa = OgnlRuntime.getPropertyAccessor(context.getCurrentObject().getClass());
if (context.getCurrentObject().getClass().isArray()) {
if (pd == null) {
pd = OgnlRuntime.getProperty(context.getCurrentObject().getClass(), name);
if (pd != null && pd.getReadMethod() != null) {
m = pd.getReadMethod();
result = pd.getName();
} else {
getterClass = int.class;
context.setCurrentAccessor(context.getCurrentObject().getClass());
context.setCurrentType(int.class);
result = "." + name;
}
}
} else {
if (pd != null && pd.getReadMethod() != null) {
m = pd.getReadMethod();
result = "." + m.getName() + "()";
} else if (pa != null) {
Object currObj = context.getCurrentObject();
Class> currType = context.getCurrentType();
Class> prevType = context.getPreviousType();
String srcString = children[0].toGetSourceString(context, context.getRoot());
if (children[0] instanceof ASTConst && context.getCurrentObject() instanceof String) {
srcString = "\"" + srcString + "\"";
}
context.setCurrentObject(currObj);
context.setCurrentType(currType);
context.setPreviousType(prevType);
result = pa.getSourceAccessor(context, context.getCurrentObject(), srcString);
getterClass = context.getCurrentType();
}
}
}
} catch (Throwable t) {
throw OgnlOps.castToRuntime(t);
}
// set known property types for NodeType interface when possible
if (m != null) {
getterClass = m.getReturnType();
context.setCurrentType(m.getReturnType());
context.setCurrentAccessor(OgnlRuntime.getCompiler().getSuperOrInterfaceClass(m, m.getDeclaringClass()));
}
context.setCurrentObject(target);
return result;
}
Method getIndexedWriteMethod(PropertyDescriptor pd) {
if (pd instanceof IndexedPropertyDescriptor) {
return ((IndexedPropertyDescriptor) pd).getIndexedWriteMethod();
} else if (pd instanceof ObjectIndexedPropertyDescriptor) {
return ((ObjectIndexedPropertyDescriptor) pd).getIndexedWriteMethod();
}
return null;
}
public String toSetSourceString(OgnlContext context, Object target) {
String result = "";
Method m = null;
if (context.getCurrentObject() == null)
throw new UnsupportedCompilationException("Current target is null.");
/*System.out.println("astproperty(setter) is indexed? : " + isIndexedAccess() + " child: " + _children[0].getClass().getName()
+ " target: " + target.getClass().getName() + " children length: " + _children.length);*/
try {
if (isIndexedAccess()) {
Object value = children[0].getValue(context, context.getRoot());
if (value == null)
throw new UnsupportedCompilationException("Value passed as indexed property is null, can't enhance statement to bytecode.");
String srcString = children[0].toGetSourceString(context, context.getRoot());
srcString = ExpressionCompiler.getRootExpression(children[0], context.getRoot(), context) + srcString;
if (children[0] instanceof ASTChain) {
String cast = (String) context.remove(ExpressionCompiler.PRE_CAST);
if (cast != null)
srcString = cast + srcString;
}
if (children[0] instanceof ASTConst && context.getCurrentObject() instanceof String) {
srcString = "\"" + srcString + "\"";
}
// System.out.println("astproperty setter using indexed value " + value + " and srcString: " + srcString);
if (context.get("_indexedMethod") != null) {
m = (Method) context.remove("_indexedMethod");
PropertyDescriptor pd = (PropertyDescriptor) context.remove("_indexedDescriptor");
boolean lastChild = lastChild(context);
if (lastChild) {
m = getIndexedWriteMethod(pd);
if (m == null)
throw new UnsupportedCompilationException("Indexed property has no corresponding write method.");
}
setterClass = m.getParameterTypes()[0];
Object indexedValue = null;
if (!lastChild)
indexedValue = OgnlRuntime.callMethod(context, target, m.getName(), new Object[]{value});
context.setCurrentType(setterClass);
context.setCurrentAccessor(OgnlRuntime.getCompiler().getSuperOrInterfaceClass(m, m.getDeclaringClass()));
if (!lastChild) {
context.setCurrentObject(indexedValue);
return "." + m.getName() + "(" + srcString + ")";
} else {
return "." + m.getName() + "(" + srcString + ", $3)";
}
} else {
PropertyAccessor p = OgnlRuntime.getPropertyAccessor(target.getClass());
Object currObj = context.getCurrentObject();
Class> currType = context.getCurrentType();
Class> prevType = context.getPreviousType();
Object indexVal = p.getProperty(context, target, value);
// reset current object for accessor
context.setCurrentObject(currObj);
context.setCurrentType(currType);
context.setPreviousType(prevType);
if (children[0] instanceof ASTConst && context.getCurrentObject() instanceof Number)
context.setCurrentType(OgnlRuntime.getPrimitiveWrapperClass(context.getCurrentObject().getClass()));
result = lastChild(context) ? p.getSourceSetter(context, target, srcString) : p.getSourceAccessor(context, target, srcString);
getterClass = context.getCurrentType();
context.setCurrentObject(indexVal);
return result;
}
}
String name = ((ASTConst) children[0]).getValue().toString();
// System.out.println(" astprop(setter) : trying to set " + name + " on object target " + context.getCurrentObject().getClass().getName());
if (!Iterator.class.isAssignableFrom(context.getCurrentObject().getClass())
|| (Iterator.class.isAssignableFrom(context.getCurrentObject().getClass()) && !name.contains("next"))) {
Object currObj = target;
try {
target = getValue(context, context.getCurrentObject());
} catch (NoSuchPropertyException e) {
try {
target = getValue(context, context.getRoot());
} catch (NoSuchPropertyException ignored) {
}
} finally {
context.setCurrentObject(currObj);
}
}
PropertyDescriptor pd = OgnlRuntime.getPropertyDescriptor(OgnlRuntime.getCompiler().getInterfaceClass(context.getCurrentObject().getClass()), name);
if (pd != null) {
Method pdMethod = lastChild(context) ? pd.getWriteMethod() : pd.getReadMethod();
if (pdMethod != null && !context.getMemberAccess().isAccessible(context, context.getCurrentObject(), pdMethod, name)) {
throw new UnsupportedCompilationException("Member access forbidden for property " + name + " on class " + context.getCurrentObject().getClass());
}
}
if (pd != null && this.getIndexedPropertyType(context, context.getCurrentObject()) > 0) {
// if an indexed method accessor need to use special property descriptors to find methods
if (pd instanceof IndexedPropertyDescriptor) {
IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
m = lastChild(context) ? ipd.getIndexedWriteMethod() : ipd.getIndexedReadMethod();
} else {
if (pd instanceof ObjectIndexedPropertyDescriptor) {
ObjectIndexedPropertyDescriptor opd = (ObjectIndexedPropertyDescriptor) pd;
m = lastChild(context) ? opd.getIndexedWriteMethod() : opd.getIndexedReadMethod();
} else {
throw new OgnlException("property '" + name + "' is not an indexed property");
}
}
if (parent == null) {
// the above pd will be the wrong result sometimes, such as methods like getValue(int) vs String[] getValue()
m = OgnlRuntime.getWriteMethod(context.getCurrentObject().getClass(), name);
Class> parm = m.getParameterTypes()[0];
String cast = parm.isArray() ? ExpressionCompiler.getCastString(parm) : parm.getName();
result = m.getName() + "((" + cast + ")$3)";
setterClass = parm;
} else {
context.put("_indexedMethod", m);
context.put("_indexedDescriptor", pd);
}
} else {
PropertyAccessor pa = OgnlRuntime.getPropertyAccessor(context.getCurrentObject().getClass());
/*System.out.println("astproperty trying to set " + name + " on object target: " + context.getCurrentObject().getClass().getName()
+ " using propertyaccessor type: " + pa);*/
if (target != null)
setterClass = target.getClass();
if (parent != null && pd != null && pa == null) {
m = pd.getReadMethod();
result = m.getName() + "()";
} else {
if (context.getCurrentObject().getClass().isArray()) {
result = "";
} else if (pa != null) {
Object currObj = context.getCurrentObject();
//Class currType = context.getCurrentType();
//Class prevType = context.getPreviousType();
String srcString = children[0].toGetSourceString(context, context.getRoot());
if (children[0] instanceof ASTConst && context.getCurrentObject() instanceof String) {
srcString = "\"" + srcString + "\"";
}
context.setCurrentObject(currObj);
//context.setCurrentType(currType);
//context.setPreviousType(prevType);
if (!lastChild(context)) {
result = pa.getSourceAccessor(context, context.getCurrentObject(), srcString);
} else {
result = pa.getSourceSetter(context, context.getCurrentObject(), srcString);
}
getterClass = context.getCurrentType();
}
}
}
} catch (Throwable t) {
throw OgnlOps.castToRuntime(t);
}
context.setCurrentObject(target);
if (m != null) {
context.setCurrentType(m.getReturnType());
context.setCurrentAccessor(OgnlRuntime.getCompiler().getSuperOrInterfaceClass(m, m.getDeclaringClass()));
}
return result;
}
}