You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2022/08/30 14:52:51 UTC
[commons-ognl] branch master updated: Move Apache license header to the top of the file
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-ognl.git
The following commit(s) were added to refs/heads/master by this push:
new 1d2048d Move Apache license header to the top of the file
1d2048d is described below
commit 1d2048db25b79b3f53b969f5b3971e0d7c17d797
Author: Gary Gregory <gg...@rocketsoftware.com>
AuthorDate: Tue Aug 30 10:52:47 2022 -0400
Move Apache license header to the top of the file
---
.../commons/ognl/enhance/ContextClassLoader.java | 114 +-
.../commons/ognl/enhance/EnhancedClassLoader.java | 84 +-
.../commons/ognl/enhance/ExpressionAccessor.java | 116 +-
.../commons/ognl/enhance/ExpressionCompiler.java | 1690 ++++++++++----------
.../commons/ognl/enhance/LocalReference.java | 96 +-
.../commons/ognl/enhance/LocalReferenceImpl.java | 242 +--
.../ognl/enhance/OgnlExpressionCompiler.java | 250 +--
.../apache/commons/ognl/enhance/OrderedReturn.java | 87 +-
.../enhance/UnsupportedCompilationException.java | 96 +-
.../apache/commons/ognl/enhance/package-info.java | 48 +-
10 files changed, 1411 insertions(+), 1412 deletions(-)
diff --git a/src/main/java/org/apache/commons/ognl/enhance/ContextClassLoader.java b/src/main/java/org/apache/commons/ognl/enhance/ContextClassLoader.java
index 1c5d765..f8814f1 100644
--- a/src/main/java/org/apache/commons/ognl/enhance/ContextClassLoader.java
+++ b/src/main/java/org/apache/commons/ognl/enhance/ContextClassLoader.java
@@ -1,57 +1,57 @@
-package org.apache.commons.ognl.enhance;
-
-/*
- * 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.
- */
-
-import org.apache.commons.ognl.OgnlContext;
-
-public class ContextClassLoader
- extends ClassLoader
-{
- private final OgnlContext context;
-
- /*
- * =================================================================== Constructors
- * ===================================================================
- */
- public ContextClassLoader( ClassLoader parentClassLoader, OgnlContext context )
- {
- super( parentClassLoader );
- this.context = context;
- }
-
- /*
- * =================================================================== Overridden methods
- * ===================================================================
- */
- /**
- * {@inheritDoc}
- */
- @Override
- protected Class<?> findClass( String name )
- throws ClassNotFoundException
- {
- if ( ( context != null ) && ( context.getClassResolver() != null ) )
- {
- return context.getClassResolver().classForName( name, context );
- }
- return super.findClass( name );
- }
-
-}
+/*
+ * 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.commons.ognl.enhance;
+
+import org.apache.commons.ognl.OgnlContext;
+
+public class ContextClassLoader
+ extends ClassLoader
+{
+ private final OgnlContext context;
+
+ /*
+ * =================================================================== Constructors
+ * ===================================================================
+ */
+ public ContextClassLoader( ClassLoader parentClassLoader, OgnlContext context )
+ {
+ super( parentClassLoader );
+ this.context = context;
+ }
+
+ /*
+ * =================================================================== Overridden methods
+ * ===================================================================
+ */
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Class<?> findClass( String name )
+ throws ClassNotFoundException
+ {
+ if ( ( context != null ) && ( context.getClassResolver() != null ) )
+ {
+ return context.getClassResolver().classForName( name, context );
+ }
+ return super.findClass( name );
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/ognl/enhance/EnhancedClassLoader.java b/src/main/java/org/apache/commons/ognl/enhance/EnhancedClassLoader.java
index 84cb8db..8470a82 100644
--- a/src/main/java/org/apache/commons/ognl/enhance/EnhancedClassLoader.java
+++ b/src/main/java/org/apache/commons/ognl/enhance/EnhancedClassLoader.java
@@ -1,42 +1,42 @@
-package org.apache.commons.ognl.enhance;
-
-/*
- * 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.
- */
-
-public class EnhancedClassLoader
- extends ClassLoader
-{
- /*
- * =================================================================== Constructors
- * ===================================================================
- */
- public EnhancedClassLoader( ClassLoader parentClassLoader )
- {
- super( parentClassLoader );
- }
-
- /*
- * =================================================================== Overridden methods
- * ===================================================================
- */
- public Class<?> defineClass( String enhancedClassName, byte[] byteCode )
- {
- return defineClass( enhancedClassName, byteCode, 0, byteCode.length );
- }
-}
+/*
+ * 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.commons.ognl.enhance;
+
+public class EnhancedClassLoader
+ extends ClassLoader
+{
+ /*
+ * =================================================================== Constructors
+ * ===================================================================
+ */
+ public EnhancedClassLoader( ClassLoader parentClassLoader )
+ {
+ super( parentClassLoader );
+ }
+
+ /*
+ * =================================================================== Overridden methods
+ * ===================================================================
+ */
+ public Class<?> defineClass( String enhancedClassName, byte[] byteCode )
+ {
+ return defineClass( enhancedClassName, byteCode, 0, byteCode.length );
+ }
+}
diff --git a/src/main/java/org/apache/commons/ognl/enhance/ExpressionAccessor.java b/src/main/java/org/apache/commons/ognl/enhance/ExpressionAccessor.java
index 7b51efc..6905516 100644
--- a/src/main/java/org/apache/commons/ognl/enhance/ExpressionAccessor.java
+++ b/src/main/java/org/apache/commons/ognl/enhance/ExpressionAccessor.java
@@ -1,58 +1,58 @@
-package org.apache.commons.ognl.enhance;
-
-/*
- * 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.
- */
-
-import org.apache.commons.ognl.Node;
-import org.apache.commons.ognl.OgnlContext;
-
-/**
- * Provides pure java expression paths to get/set values from an ognl expression. This is achieved by taking an existing
- * {@link Node} parsed expression and using bytecode enhancements to do the same work using pure java vs the ognl
- * interpreter.
- */
-public interface ExpressionAccessor
-{
-
- /**
- * Gets the value represented by this expression path, if any.
- *
- * @param context The standard ognl context used for variable substitution/etc.
- * @param target The root object this expression is meant for.
- * @return The evaluated value, if any.
- */
- Object get( OgnlContext context, Object target );
-
- /**
- * Sets the value represented by this expression path, if possible.
- *
- * @param context The standard ognl context used for variable substitution/etc.
- * @param target The root object this expression is meant for.
- * @param value The new value to set if this expression references a settable property.
- */
- void set( OgnlContext context, Object target, Object value );
-
- /**
- * Used to set the original root expression node on instances where the compiled version has to fall back to
- * interpreted syntax because of compilation failures.
- *
- * @param expression The root expression node used to generate this accessor.
- */
- void setExpression( Node expression );
-}
+/*
+ * 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.commons.ognl.enhance;
+
+import org.apache.commons.ognl.Node;
+import org.apache.commons.ognl.OgnlContext;
+
+/**
+ * Provides pure java expression paths to get/set values from an ognl expression. This is achieved by taking an existing
+ * {@link Node} parsed expression and using bytecode enhancements to do the same work using pure java vs the ognl
+ * interpreter.
+ */
+public interface ExpressionAccessor
+{
+
+ /**
+ * Gets the value represented by this expression path, if any.
+ *
+ * @param context The standard ognl context used for variable substitution/etc.
+ * @param target The root object this expression is meant for.
+ * @return The evaluated value, if any.
+ */
+ Object get( OgnlContext context, Object target );
+
+ /**
+ * Sets the value represented by this expression path, if possible.
+ *
+ * @param context The standard ognl context used for variable substitution/etc.
+ * @param target The root object this expression is meant for.
+ * @param value The new value to set if this expression references a settable property.
+ */
+ void set( OgnlContext context, Object target, Object value );
+
+ /**
+ * Used to set the original root expression node on instances where the compiled version has to fall back to
+ * interpreted syntax because of compilation failures.
+ *
+ * @param expression The root expression node used to generate this accessor.
+ */
+ void setExpression( Node expression );
+}
diff --git a/src/main/java/org/apache/commons/ognl/enhance/ExpressionCompiler.java b/src/main/java/org/apache/commons/ognl/enhance/ExpressionCompiler.java
index 628af40..e75eadc 100644
--- a/src/main/java/org/apache/commons/ognl/enhance/ExpressionCompiler.java
+++ b/src/main/java/org/apache/commons/ognl/enhance/ExpressionCompiler.java
@@ -1,845 +1,845 @@
-package org.apache.commons.ognl.enhance;
-
-/*
- * 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.
- */
-
-import javassist.CannotCompileException;
-import javassist.ClassPool;
-import javassist.CtClass;
-import javassist.CtField;
-import javassist.CtMethod;
-import javassist.CtNewConstructor;
-import javassist.CtNewMethod;
-import javassist.LoaderClassPath;
-import javassist.NotFoundException;
-import org.apache.commons.ognl.ASTAnd;
-import org.apache.commons.ognl.ASTChain;
-import org.apache.commons.ognl.ASTConst;
-import org.apache.commons.ognl.ASTCtor;
-import org.apache.commons.ognl.ASTList;
-import org.apache.commons.ognl.ASTMethod;
-import org.apache.commons.ognl.ASTOr;
-import org.apache.commons.ognl.ASTProperty;
-import org.apache.commons.ognl.ASTRootVarRef;
-import org.apache.commons.ognl.ASTStaticField;
-import org.apache.commons.ognl.ASTStaticMethod;
-import org.apache.commons.ognl.ASTThisVarRef;
-import org.apache.commons.ognl.ASTVarRef;
-import org.apache.commons.ognl.ClassResolver;
-import org.apache.commons.ognl.ExpressionNode;
-import org.apache.commons.ognl.Node;
-import org.apache.commons.ognl.OgnlContext;
-import org.apache.commons.ognl.OgnlRuntime;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static java.lang.String.format;
-
-/**
- * Responsible for managing/providing functionality related to compiling generated java source expressions via bytecode
- * enhancements for a given ognl expression.
- */
-public class ExpressionCompiler
- implements OgnlExpressionCompiler
-{
-
- /**
- * Key used to store any java source string casting statements in the {@link OgnlContext} during class compilation.
- */
- public static final String PRE_CAST = "_preCast";
-
- /**
- * {@link ClassLoader} instances.
- */
- protected Map<ClassResolver, EnhancedClassLoader> loaders = new HashMap<ClassResolver, EnhancedClassLoader>();
-
- /**
- * Javassist class definition poool.
- */
- protected ClassPool pool;
-
- protected int classCounter = 0;
-
- /**
- * Used by {@link #castExpression(org.apache.commons.ognl.OgnlContext, org.apache.commons.ognl.Node, String)} to
- * store the cast java source string in to the current {@link org.apache.commons.ognl.OgnlContext}. This will either
- * add to the existing string present if it already exists or create a new instance and store it using the static
- * key of {@link #PRE_CAST}.
- *
- * @param context The current execution context.
- * @param cast The java source string to store in to the context.
- */
- public static void addCastString( OgnlContext context, String cast )
- {
- String value = (String) context.get( PRE_CAST );
-
- if ( value != null )
- {
- value = cast + value;
- }
- else
- {
- value = cast;
- }
-
- context.put( PRE_CAST, value );
- }
-
- /**
- * Returns the appropriate casting expression (minus parens) for the specified class type.
- * <p/>
- * For instance, if given an {@link Integer} object the string <code>"java.lang.Integer"</code> would be returned.
- * For an array of primitive ints <code>"int[]"</code> and so on..
- * </p>
- *
- * @param type The class to cast a string expression for.
- * @return The converted raw string version of the class name.
- */
- public static String getCastString( Class<?> type )
- {
- if ( type == null )
- {
- return null;
- }
-
- return type.isArray() ? type.getComponentType().getName() + "[]" : type.getName();
- }
-
- /**
- * Convenience method called by many different property/method resolving AST types to get a root expression
- * resolving string for the given node. The callers are mostly ignorant and rely on this method to properly
- * determine if the expression should be cast at all and take the appropriate actions if it should.
- *
- * @param expression The node to check and generate a root expression to if necessary.
- * @param root The root object for this execution.
- * @param context The current execution context.
- * @return Either an empty string or a root path java source string compatible with javassist compilations from the
- * root object up to the specified {@link Node}.
- */
- public static String getRootExpression( Node expression, Object root, OgnlContext context )
- {
- String rootExpr = "";
-
- if ( !shouldCast( expression ) )
- {
- return rootExpr;
- }
-
- if ( ( !(expression instanceof ASTList) && !(expression instanceof ASTVarRef)
- && !(expression instanceof ASTStaticMethod) && !(expression instanceof ASTStaticField)
- && !(expression instanceof ASTConst) && !(expression instanceof ExpressionNode)
- && !(expression instanceof ASTCtor) && !(expression instanceof ASTStaticMethod)
- && root != null ) || ( root != null && expression instanceof ASTRootVarRef) )
- {
-
- Class<?> castClass = OgnlRuntime.getCompiler( context ).getRootExpressionClass( expression, context );
-
- if ( castClass.isArray() || expression instanceof ASTRootVarRef || expression instanceof ASTThisVarRef)
- {
- rootExpr = "((" + getCastString( castClass ) + ")$2)";
-
- if ( expression instanceof ASTProperty && !( (ASTProperty) expression ).isIndexedAccess() )
- {
- rootExpr += ".";
- }
- }
- else if ( ( expression instanceof ASTProperty && ( (ASTProperty) expression ).isIndexedAccess() )
- || expression instanceof ASTChain)
- {
- rootExpr = "((" + getCastString( castClass ) + ")$2)";
- }
- else
- {
- rootExpr = "((" + getCastString( castClass ) + ")$2).";
- }
- }
-
- return rootExpr;
- }
-
- /**
- * Used by {@link #getRootExpression(org.apache.commons.ognl.Node, Object, org.apache.commons.ognl.OgnlContext)} to
- * determine if the expression needs to be cast at all.
- *
- * @param expression The node to check against.
- * @return Yes if the node type should be cast - false otherwise.
- */
- public static boolean shouldCast( Node expression )
- {
- if (expression instanceof ASTChain)
- {
- Node child = expression.jjtGetChild( 0 );
- if ( child instanceof ASTConst || child instanceof ASTStaticMethod
- || child instanceof ASTStaticField || ( child instanceof ASTVarRef
- && !(child instanceof ASTRootVarRef)) )
- {
- return false;
- }
- }
-
- return !(expression instanceof ASTConst);
- }
-
- /**
- * {@inheritDoc}
- */
- public String castExpression( OgnlContext context, Node expression, String body )
- {
- //TODO: ok - so this looks really f-ed up ...and it is ..eh if you can do it better I'm all for it :)
-
- if ( context.getCurrentAccessor() == null || context.getPreviousType() == null
- || context.getCurrentAccessor().isAssignableFrom( context.getPreviousType() ) || (
- context.getCurrentType() != null && context.getCurrentObject() != null
- && context.getCurrentType().isAssignableFrom( context.getCurrentObject().getClass() )
- && context.getCurrentAccessor().isAssignableFrom( context.getPreviousType() ) ) || body == null
- || body.trim().length() < 1 || ( context.getCurrentType() != null && context.getCurrentType().isArray() && (
- context.getPreviousType() == null || context.getPreviousType() != Object.class ) )
- || expression instanceof ASTOr || expression instanceof ASTAnd
- || expression instanceof ASTRootVarRef || context.getCurrentAccessor() == Class.class || (
- context.get( ExpressionCompiler.PRE_CAST ) != null && ( (String) context.get(
- ExpressionCompiler.PRE_CAST ) ).startsWith( "new" ) ) || expression instanceof ASTStaticField
- || expression instanceof ASTStaticMethod || ( expression instanceof OrderedReturn
- && ( (OrderedReturn) expression ).getLastExpression() != null ) )
- {
- return body;
- }
-
- /*
- * System.out.println("castExpression() with expression " + expression + " expr class: " + expression.getClass()
- * + " currentType is: " + context.getCurrentType() + " previousType: " + context.getPreviousType() +
- * "\n current Accessor: " + context.getCurrentAccessor() + " previous Accessor: " +
- * context.getPreviousAccessor() + " current object " + context.getCurrentObject());
- */
-
- ExpressionCompiler.addCastString( context,
- "((" + ExpressionCompiler.getCastString( context.getCurrentAccessor() )
- + ")" );
-
- return ")" + body;
- }
-
- /**
- * {@inheritDoc}
- */
- public String getClassName( Class<?> clazz )
- {
- if ( "java.util.AbstractList$Itr".equals( clazz.getName() ) )
- {
- return Iterator.class.getName();
- }
-
- if ( Modifier.isPublic( clazz.getModifiers() ) && clazz.isInterface() )
- {
- return clazz.getName();
- }
-
- Class<?>[] interfaces = clazz.getInterfaces();
-
- for ( Class<?> intface : interfaces )
- {
- if ( intface.getName().indexOf( "util.List" ) > 0 )
- {
- return intface.getName();
- }
- if ( intface.getName().indexOf( "Iterator" ) > 0 )
- {
- return intface.getName();
- }
- }
-
- if ( clazz.getSuperclass() != null && clazz.getSuperclass().getInterfaces().length > 0 )
- {
- return getClassName( clazz.getSuperclass() );
- }
-
- return clazz.getName();
- }
-
- /**
- * {@inheritDoc}
- */
- public Class<?> getSuperOrInterfaceClass( Method m, Class<?> clazz )
- {
- if ( clazz.getInterfaces() != null && clazz.getInterfaces().length > 0 )
- {
- Class<?>[] intfs = clazz.getInterfaces();
- Class<?> intClass;
-
- for ( Class<?> intf : intfs )
- {
- intClass = getSuperOrInterfaceClass( m, intf );
-
- if ( intClass != null )
- {
- return intClass;
- }
-
- if ( Modifier.isPublic( intf.getModifiers() ) && containsMethod( m, intf ) )
- {
- return intf;
- }
- }
- }
-
- if ( clazz.getSuperclass() != null )
- {
- Class<?> superClass = getSuperOrInterfaceClass( m, clazz.getSuperclass() );
-
- if ( superClass != null )
- {
- return superClass;
- }
- }
-
- if ( Modifier.isPublic( clazz.getModifiers() ) && containsMethod( m, clazz ) )
- {
- return clazz;
- }
-
- return null;
- }
-
- /**
- * Helper utility method used by compiler to help resolve class->method mappings during method calls to
- * {@link OgnlExpressionCompiler#getSuperOrInterfaceClass(java.lang.reflect.Method, Class)}.
- *
- * @param m The method to check for existance of.
- * @param clazz The class to check for the existance of a matching method definition to the method passed in.
- * @return True if the class contains the specified method, false otherwise.
- */
- public boolean containsMethod( Method m, Class<?> clazz )
- {
- Method[] methods = clazz.getMethods();
-
- if ( methods == null )
- {
- return false;
- }
-
- for ( Method method : methods )
- {
- if ( method.getName().equals( m.getName() ) && method.getReturnType() == m.getReturnType() )
- {
- Class<?>[] parms = m.getParameterTypes();
- if ( parms == null )
- {
- continue;
- }
-
- Class<?>[] mparms = method.getParameterTypes();
- if ( mparms == null || mparms.length != parms.length )
- {
- continue;
- }
-
- boolean parmsMatch = true;
- for ( int p = 0; p < parms.length; p++ )
- {
- if ( parms[p] != mparms[p] )
- {
- parmsMatch = false;
- break;
- }
- }
-
- if ( !parmsMatch )
- {
- continue;
- }
-
- Class<?>[] exceptions = m.getExceptionTypes();
- if ( exceptions == null )
- {
- continue;
- }
-
- Class<?>[] mexceptions = method.getExceptionTypes();
- if ( mexceptions == null || mexceptions.length != exceptions.length )
- {
- continue;
- }
-
- boolean exceptionsMatch = true;
- for ( int e = 0; e < exceptions.length; e++ )
- {
- if ( exceptions[e] != mexceptions[e] )
- {
- exceptionsMatch = false;
- break;
- }
- }
-
- if ( !exceptionsMatch )
- {
- continue;
- }
-
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public Class<?> getInterfaceClass( Class<?> clazz )
- {
- if ( "java.util.AbstractList$Itr".equals( clazz.getName() ) )
- {
- return Iterator.class;
- }
-
- if ( Modifier.isPublic( clazz.getModifiers() ) && clazz.isInterface() || clazz.isPrimitive() )
- {
- return clazz;
- }
-
- Class<?>[] intf = clazz.getInterfaces();
-
- for ( Class<?> anIntf : intf )
- {
- if ( List.class.isAssignableFrom( anIntf ) )
- {
- return List.class;
- }
- if ( Iterator.class.isAssignableFrom( anIntf ) )
- {
- return Iterator.class;
- }
- if ( Map.class.isAssignableFrom( anIntf ) )
- {
- return Map.class;
- }
- if ( Set.class.isAssignableFrom( anIntf ) )
- {
- return Set.class;
- }
- if ( Collection.class.isAssignableFrom( anIntf ) )
- {
- return Collection.class;
- }
- }
-
- if ( clazz.getSuperclass() != null && clazz.getSuperclass().getInterfaces().length > 0 )
- {
- return getInterfaceClass( clazz.getSuperclass() );
- }
-
- return clazz;
- }
-
- /**
- * {@inheritDoc}
- */
- public Class<?> getRootExpressionClass( Node rootNode, OgnlContext context )
- {
- if ( context.getRoot() == null )
- {
- return null;
- }
-
- Class<?> ret = context.getRoot().getClass();
-
- if ( context.getFirstAccessor() != null && context.getFirstAccessor().isInstance( context.getRoot() ) )
- {
- ret = context.getFirstAccessor();
- }
-
- return ret;
- }
-
- /**
- * {@inheritDoc}
- */
- public void compileExpression( OgnlContext context, Node expression, Object root )
- throws Exception
- {
- // System.out.println("Compiling expr class " + expression.getClass().getName() + " and root " + root);
-
- if ( expression.getAccessor() != null )
- {
- return;
- }
-
- String getBody, setBody;
-
- EnhancedClassLoader loader = getClassLoader( context );
- ClassPool classPool = getClassPool( context, loader );
-
- CtClass newClass = classPool.makeClass(
- expression.getClass().getName() + expression.hashCode() + classCounter++ + "Accessor" );
- newClass.addInterface( getCtClass( ExpressionAccessor.class ) );
-
- CtClass ognlClass = getCtClass( OgnlContext.class );
- CtClass objClass = getCtClass( Object.class );
-
- CtMethod valueGetter = new CtMethod( objClass, "get", new CtClass[] { ognlClass, objClass }, newClass );
- CtMethod valueSetter =
- new CtMethod( CtClass.voidType, "set", new CtClass[] { ognlClass, objClass, objClass }, newClass );
-
- CtField nodeMember = null; // will only be set if uncompilable exception is thrown
-
- CtClass nodeClass = getCtClass( Node.class );
- CtMethod setExpression = null;
-
- try
- {
-
- getBody = generateGetter( context, newClass, objClass, classPool, valueGetter, expression, root );
-
- }
- catch ( UnsupportedCompilationException uc )
- {
- nodeMember = new CtField( nodeClass, "_node", newClass );
- newClass.addField( nodeMember );
-
- getBody = generateOgnlGetter( newClass, valueGetter, nodeMember );
-
- setExpression = CtNewMethod.setter( "setExpression", nodeMember );
- newClass.addMethod( setExpression );
- }
-
- try
- {
-
- setBody = generateSetter( context, newClass, objClass, classPool, valueSetter, expression, root );
-
- }
- catch ( UnsupportedCompilationException uc )
- {
- if ( nodeMember == null )
- {
- nodeMember = new CtField( nodeClass, "_node", newClass );
- newClass.addField( nodeMember );
- }
-
- setBody = generateOgnlSetter( newClass, valueSetter, nodeMember );
-
- if ( setExpression == null )
- {
- setExpression = CtNewMethod.setter( "setExpression", nodeMember );
- newClass.addMethod( setExpression );
- }
- }
-
- try
- {
- newClass.addConstructor( CtNewConstructor.defaultConstructor( newClass ) );
-
- Class<?> clazz = classPool.toClass( newClass );
- newClass.detach();
-
- expression.setAccessor( (ExpressionAccessor) clazz.newInstance() );
-
- // need to set expression on node if the field was just defined.
-
- if ( nodeMember != null )
- {
- expression.getAccessor().setExpression( expression );
- }
-
- }
- catch ( Throwable t )
- {
- throw new RuntimeException( "Error compiling expression on object " + root + " with expression node "
- + expression + " getter body: " + getBody + " setter body: " + setBody, t );
- }
-
- }
-
- protected String generateGetter( OgnlContext context, CtClass newClass, CtClass objClass, ClassPool classPool,
- CtMethod valueGetter, Node expression, Object root )
- throws Exception
- {
- String pre = "";
- String post = "";
- String body;
-
- context.setRoot( root );
-
- // the ExpressionAccessor API has to reference the generic Object class for get/set operations, so this sets up
- // that known
- // type beforehand
-
- context.remove( PRE_CAST );
-
- // Recursively generate the java source code representation of the top level expression
-
- String getterCode = expression.toGetSourceString( context, root );
-
- if ( getterCode == null || getterCode.trim().isEmpty()
- && !ASTVarRef.class.isAssignableFrom( expression.getClass() ) )
- {
- getterCode = "null";
- }
-
- String castExpression = (String) context.get( PRE_CAST );
-
- if ( context.getCurrentType() == null || context.getCurrentType().isPrimitive()
- || Character.class.isAssignableFrom( context.getCurrentType() )
- || Object.class == context.getCurrentType() )
- {
- pre = pre + " ($w) (";
- post = post + ")";
- }
-
- String rootExpr = !"null".equals( getterCode ) ? getRootExpression( expression, root, context ) : "";
-
- String noRoot = (String) context.remove( "_noRoot" );
- if ( noRoot != null )
- {
- rootExpr = "";
- }
-
- createLocalReferences( context, classPool, newClass, objClass, valueGetter.getParameterTypes() );
-
- if ( expression instanceof OrderedReturn
- && ( (OrderedReturn) expression ).getLastExpression() != null )
- {
- body = "{ " + ( expression instanceof ASTMethod || expression instanceof ASTChain
- ? rootExpr
- : "" ) + ( castExpression != null ? castExpression : "" )
- + ( (OrderedReturn) expression ).getCoreExpression() + " return " + pre
- + ( (OrderedReturn) expression ).getLastExpression() + post + ";}";
-
- }
- else
- {
-
- body =
- "{ return " + pre + ( castExpression != null ? castExpression : "" ) + rootExpr + getterCode + post
- + ";}";
- }
-
- body = body.replaceAll( "\\.\\.", "." );
-
- // System.out.println("Getter Body: ===================================\n" + body);
- valueGetter.setBody( body );
- newClass.addMethod( valueGetter );
-
- return body;
- }
-
- /**
- * {@inheritDoc}
- */
- public String createLocalReference( OgnlContext context, String expression, Class<?> type )
- {
- String referenceName = "ref" + context.incrementLocalReferenceCounter();
- context.addLocalReference( referenceName, new LocalReferenceImpl( referenceName, expression, type ) );
-
- String castString = "";
- if ( !type.isPrimitive() )
- {
- castString = "(" + ExpressionCompiler.getCastString( type ) + ") ";
- }
-
- return castString + referenceName + "($$)";
- }
-
- void createLocalReferences( OgnlContext context, ClassPool classPool, CtClass clazz, CtClass unused,
- CtClass[] params )
- throws NotFoundException, CannotCompileException
- {
- Map<String, LocalReference> referenceMap = context.getLocalReferences();
- if ( referenceMap == null || referenceMap.isEmpty() )
- {
- return;
- }
-
- Iterator<LocalReference> it = referenceMap.values().iterator();
- while( it.hasNext() )
- {
- LocalReference ref = it.next();
- String widener = ref.getType().isPrimitive() ? " " : " ($w) ";
-
- String body = format( "{ return %s %s; }", widener, ref.getExpression() ).replaceAll( "\\.\\.", "." );
-
- // System.out.println("adding method " + ref.getName() + " with body:\n" + body + " and return type: " +
- // ref.getType());
-
- CtMethod method =
- new CtMethod( classPool.get( getCastString( ref.getType() ) ), ref.getName(), params, clazz );
- method.setBody( body );
-
- clazz.addMethod( method );
- it.remove();
- }
- }
-
- protected String generateSetter( OgnlContext context, CtClass newClass, CtClass objClass, ClassPool classPool,
- CtMethod valueSetter, Node expression, Object root )
- throws Exception
- {
- if ( expression instanceof ExpressionNode || expression instanceof ASTConst)
- {
- throw new UnsupportedCompilationException( "Can't compile expression/constant setters." );
- }
-
- context.setRoot( root );
- context.remove( PRE_CAST );
-
- String body;
-
- String setterCode = expression.toSetSourceString( context, root );
- String castExpression = (String) context.get( PRE_CAST );
-
- if ( setterCode == null || setterCode.trim().length() < 1 )
- {
- throw new UnsupportedCompilationException( "Can't compile null setter body." );
- }
-
- if ( root == null )
- {
- throw new UnsupportedCompilationException( "Can't compile setters with a null root object." );
- }
-
- String pre = getRootExpression( expression, root, context );
-
- String noRoot = (String) context.remove( "_noRoot" );
- if ( noRoot != null )
- {
- pre = "";
- }
-
- createLocalReferences( context, classPool, newClass, objClass, valueSetter.getParameterTypes() );
-
- body = "{" + ( castExpression != null ? castExpression : "" ) + pre + setterCode + ";}";
-
- body = body.replaceAll( "\\.\\.", "." );
-
- // System.out.println("Setter Body: ===================================\n" + body);
-
- valueSetter.setBody( body );
- newClass.addMethod( valueSetter );
-
- return body;
- }
-
- /**
- * Fail safe getter creation when normal compilation fails.
- *
- * @param clazz The javassist class the new method should be attached to.
- * @param valueGetter The method definition the generated code will be contained within.
- * @param node The root expression node.
- * @return The generated source string for this method, the method will still be added via the javassist API either
- * way so this is really a convenience for exception reporting / debugging.
- * @throws Exception If a javassist error occurs.
- */
- protected String generateOgnlGetter( CtClass clazz, CtMethod valueGetter, CtField node )
- throws Exception
- {
- String body = "return " + node.getName() + ".getValue($1, $2);";
-
- valueGetter.setBody( body );
- clazz.addMethod( valueGetter );
-
- return body;
- }
-
- /**
- * Fail safe setter creation when normal compilation fails.
- *
- * @param clazz The javassist class the new method should be attached to.
- * @param valueSetter The method definition the generated code will be contained within.
- * @param node The root expression node.
- * @return The generated source string for this method, the method will still be added via the javassist API either
- * way so this is really a convenience for exception reporting / debugging.
- * @throws Exception If a javassist error occurs.
- */
- protected String generateOgnlSetter( CtClass clazz, CtMethod valueSetter, CtField node )
- throws Exception
- {
- String body = node.getName() + ".setValue($1, $2, $3);";
-
- valueSetter.setBody( body );
- clazz.addMethod( valueSetter );
-
- return body;
- }
-
- /**
- * Creates a {@link ClassLoader} instance compatible with the javassist classloader and normal OGNL class resolving
- * semantics.
- *
- * @param context The current execution context.
- * @return The created {@link ClassLoader} instance.
- */
- protected EnhancedClassLoader getClassLoader( OgnlContext context )
- {
- EnhancedClassLoader ret = loaders.get( context.getClassResolver() );
-
- if ( ret != null )
- {
- return ret;
- }
-
- ClassLoader classLoader = new ContextClassLoader( OgnlContext.class.getClassLoader(), context );
-
- ret = new EnhancedClassLoader( classLoader );
- loaders.put( context.getClassResolver(), ret );
-
- return ret;
- }
-
- /**
- * Loads a new class definition via javassist for the specified class.
- *
- * @param searchClass The class to load.
- * @return The javassist class equivalent.
- * @throws javassist.NotFoundException When the class definition can't be found.
- */
- protected CtClass getCtClass( Class<?> searchClass )
- throws NotFoundException
- {
- return pool.get( searchClass.getName() );
- }
-
- /**
- * Gets either a new or existing {@link ClassPool} for use in compiling javassist classes. A new class path object
- * is inserted in to the returned {@link ClassPool} using the passed in <code>loader</code> instance if a new pool
- * needs to be created.
- *
- * @param context The current execution context.
- * @param loader The {@link ClassLoader} instance to use - as returned by
- * {@link #getClassLoader(org.apache.commons.ognl.OgnlContext)}.
- * @return The existing or new {@link ClassPool} instance.
- */
- protected ClassPool getClassPool( OgnlContext context, EnhancedClassLoader loader )
- {
- if ( pool != null )
- {
- return pool;
- }
-
- pool = ClassPool.getDefault();
- pool.insertClassPath( new LoaderClassPath( loader.getParent() ) );
-
- return pool;
- }
-}
+/*
+ * 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.commons.ognl.enhance;
+
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+import javassist.CtNewConstructor;
+import javassist.CtNewMethod;
+import javassist.LoaderClassPath;
+import javassist.NotFoundException;
+import org.apache.commons.ognl.ASTAnd;
+import org.apache.commons.ognl.ASTChain;
+import org.apache.commons.ognl.ASTConst;
+import org.apache.commons.ognl.ASTCtor;
+import org.apache.commons.ognl.ASTList;
+import org.apache.commons.ognl.ASTMethod;
+import org.apache.commons.ognl.ASTOr;
+import org.apache.commons.ognl.ASTProperty;
+import org.apache.commons.ognl.ASTRootVarRef;
+import org.apache.commons.ognl.ASTStaticField;
+import org.apache.commons.ognl.ASTStaticMethod;
+import org.apache.commons.ognl.ASTThisVarRef;
+import org.apache.commons.ognl.ASTVarRef;
+import org.apache.commons.ognl.ClassResolver;
+import org.apache.commons.ognl.ExpressionNode;
+import org.apache.commons.ognl.Node;
+import org.apache.commons.ognl.OgnlContext;
+import org.apache.commons.ognl.OgnlRuntime;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static java.lang.String.format;
+
+/**
+ * Responsible for managing/providing functionality related to compiling generated java source expressions via bytecode
+ * enhancements for a given ognl expression.
+ */
+public class ExpressionCompiler
+ implements OgnlExpressionCompiler
+{
+
+ /**
+ * Key used to store any java source string casting statements in the {@link OgnlContext} during class compilation.
+ */
+ public static final String PRE_CAST = "_preCast";
+
+ /**
+ * {@link ClassLoader} instances.
+ */
+ protected Map<ClassResolver, EnhancedClassLoader> loaders = new HashMap<ClassResolver, EnhancedClassLoader>();
+
+ /**
+ * Javassist class definition poool.
+ */
+ protected ClassPool pool;
+
+ protected int classCounter = 0;
+
+ /**
+ * Used by {@link #castExpression(org.apache.commons.ognl.OgnlContext, org.apache.commons.ognl.Node, String)} to
+ * store the cast java source string in to the current {@link org.apache.commons.ognl.OgnlContext}. This will either
+ * add to the existing string present if it already exists or create a new instance and store it using the static
+ * key of {@link #PRE_CAST}.
+ *
+ * @param context The current execution context.
+ * @param cast The java source string to store in to the context.
+ */
+ public static void addCastString( OgnlContext context, String cast )
+ {
+ String value = (String) context.get( PRE_CAST );
+
+ if ( value != null )
+ {
+ value = cast + value;
+ }
+ else
+ {
+ value = cast;
+ }
+
+ context.put( PRE_CAST, value );
+ }
+
+ /**
+ * Returns the appropriate casting expression (minus parens) for the specified class type.
+ * <p/>
+ * For instance, if given an {@link Integer} object the string <code>"java.lang.Integer"</code> would be returned.
+ * For an array of primitive ints <code>"int[]"</code> and so on..
+ * </p>
+ *
+ * @param type The class to cast a string expression for.
+ * @return The converted raw string version of the class name.
+ */
+ public static String getCastString( Class<?> type )
+ {
+ if ( type == null )
+ {
+ return null;
+ }
+
+ return type.isArray() ? type.getComponentType().getName() + "[]" : type.getName();
+ }
+
+ /**
+ * Convenience method called by many different property/method resolving AST types to get a root expression
+ * resolving string for the given node. The callers are mostly ignorant and rely on this method to properly
+ * determine if the expression should be cast at all and take the appropriate actions if it should.
+ *
+ * @param expression The node to check and generate a root expression to if necessary.
+ * @param root The root object for this execution.
+ * @param context The current execution context.
+ * @return Either an empty string or a root path java source string compatible with javassist compilations from the
+ * root object up to the specified {@link Node}.
+ */
+ public static String getRootExpression( Node expression, Object root, OgnlContext context )
+ {
+ String rootExpr = "";
+
+ if ( !shouldCast( expression ) )
+ {
+ return rootExpr;
+ }
+
+ if ( ( !(expression instanceof ASTList) && !(expression instanceof ASTVarRef)
+ && !(expression instanceof ASTStaticMethod) && !(expression instanceof ASTStaticField)
+ && !(expression instanceof ASTConst) && !(expression instanceof ExpressionNode)
+ && !(expression instanceof ASTCtor) && !(expression instanceof ASTStaticMethod)
+ && root != null ) || ( root != null && expression instanceof ASTRootVarRef) )
+ {
+
+ Class<?> castClass = OgnlRuntime.getCompiler( context ).getRootExpressionClass( expression, context );
+
+ if ( castClass.isArray() || expression instanceof ASTRootVarRef || expression instanceof ASTThisVarRef)
+ {
+ rootExpr = "((" + getCastString( castClass ) + ")$2)";
+
+ if ( expression instanceof ASTProperty && !( (ASTProperty) expression ).isIndexedAccess() )
+ {
+ rootExpr += ".";
+ }
+ }
+ else if ( ( expression instanceof ASTProperty && ( (ASTProperty) expression ).isIndexedAccess() )
+ || expression instanceof ASTChain)
+ {
+ rootExpr = "((" + getCastString( castClass ) + ")$2)";
+ }
+ else
+ {
+ rootExpr = "((" + getCastString( castClass ) + ")$2).";
+ }
+ }
+
+ return rootExpr;
+ }
+
+ /**
+ * Used by {@link #getRootExpression(org.apache.commons.ognl.Node, Object, org.apache.commons.ognl.OgnlContext)} to
+ * determine if the expression needs to be cast at all.
+ *
+ * @param expression The node to check against.
+ * @return Yes if the node type should be cast - false otherwise.
+ */
+ public static boolean shouldCast( Node expression )
+ {
+ if (expression instanceof ASTChain)
+ {
+ Node child = expression.jjtGetChild( 0 );
+ if ( child instanceof ASTConst || child instanceof ASTStaticMethod
+ || child instanceof ASTStaticField || ( child instanceof ASTVarRef
+ && !(child instanceof ASTRootVarRef)) )
+ {
+ return false;
+ }
+ }
+
+ return !(expression instanceof ASTConst);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String castExpression( OgnlContext context, Node expression, String body )
+ {
+ //TODO: ok - so this looks really f-ed up ...and it is ..eh if you can do it better I'm all for it :)
+
+ if ( context.getCurrentAccessor() == null || context.getPreviousType() == null
+ || context.getCurrentAccessor().isAssignableFrom( context.getPreviousType() ) || (
+ context.getCurrentType() != null && context.getCurrentObject() != null
+ && context.getCurrentType().isAssignableFrom( context.getCurrentObject().getClass() )
+ && context.getCurrentAccessor().isAssignableFrom( context.getPreviousType() ) ) || body == null
+ || body.trim().length() < 1 || ( context.getCurrentType() != null && context.getCurrentType().isArray() && (
+ context.getPreviousType() == null || context.getPreviousType() != Object.class ) )
+ || expression instanceof ASTOr || expression instanceof ASTAnd
+ || expression instanceof ASTRootVarRef || context.getCurrentAccessor() == Class.class || (
+ context.get( ExpressionCompiler.PRE_CAST ) != null && ( (String) context.get(
+ ExpressionCompiler.PRE_CAST ) ).startsWith( "new" ) ) || expression instanceof ASTStaticField
+ || expression instanceof ASTStaticMethod || ( expression instanceof OrderedReturn
+ && ( (OrderedReturn) expression ).getLastExpression() != null ) )
+ {
+ return body;
+ }
+
+ /*
+ * System.out.println("castExpression() with expression " + expression + " expr class: " + expression.getClass()
+ * + " currentType is: " + context.getCurrentType() + " previousType: " + context.getPreviousType() +
+ * "\n current Accessor: " + context.getCurrentAccessor() + " previous Accessor: " +
+ * context.getPreviousAccessor() + " current object " + context.getCurrentObject());
+ */
+
+ ExpressionCompiler.addCastString( context,
+ "((" + ExpressionCompiler.getCastString( context.getCurrentAccessor() )
+ + ")" );
+
+ return ")" + body;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getClassName( Class<?> clazz )
+ {
+ if ( "java.util.AbstractList$Itr".equals( clazz.getName() ) )
+ {
+ return Iterator.class.getName();
+ }
+
+ if ( Modifier.isPublic( clazz.getModifiers() ) && clazz.isInterface() )
+ {
+ return clazz.getName();
+ }
+
+ Class<?>[] interfaces = clazz.getInterfaces();
+
+ for ( Class<?> intface : interfaces )
+ {
+ if ( intface.getName().indexOf( "util.List" ) > 0 )
+ {
+ return intface.getName();
+ }
+ if ( intface.getName().indexOf( "Iterator" ) > 0 )
+ {
+ return intface.getName();
+ }
+ }
+
+ if ( clazz.getSuperclass() != null && clazz.getSuperclass().getInterfaces().length > 0 )
+ {
+ return getClassName( clazz.getSuperclass() );
+ }
+
+ return clazz.getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Class<?> getSuperOrInterfaceClass( Method m, Class<?> clazz )
+ {
+ if ( clazz.getInterfaces() != null && clazz.getInterfaces().length > 0 )
+ {
+ Class<?>[] intfs = clazz.getInterfaces();
+ Class<?> intClass;
+
+ for ( Class<?> intf : intfs )
+ {
+ intClass = getSuperOrInterfaceClass( m, intf );
+
+ if ( intClass != null )
+ {
+ return intClass;
+ }
+
+ if ( Modifier.isPublic( intf.getModifiers() ) && containsMethod( m, intf ) )
+ {
+ return intf;
+ }
+ }
+ }
+
+ if ( clazz.getSuperclass() != null )
+ {
+ Class<?> superClass = getSuperOrInterfaceClass( m, clazz.getSuperclass() );
+
+ if ( superClass != null )
+ {
+ return superClass;
+ }
+ }
+
+ if ( Modifier.isPublic( clazz.getModifiers() ) && containsMethod( m, clazz ) )
+ {
+ return clazz;
+ }
+
+ return null;
+ }
+
+ /**
+ * Helper utility method used by compiler to help resolve class->method mappings during method calls to
+ * {@link OgnlExpressionCompiler#getSuperOrInterfaceClass(java.lang.reflect.Method, Class)}.
+ *
+ * @param m The method to check for existance of.
+ * @param clazz The class to check for the existance of a matching method definition to the method passed in.
+ * @return True if the class contains the specified method, false otherwise.
+ */
+ public boolean containsMethod( Method m, Class<?> clazz )
+ {
+ Method[] methods = clazz.getMethods();
+
+ if ( methods == null )
+ {
+ return false;
+ }
+
+ for ( Method method : methods )
+ {
+ if ( method.getName().equals( m.getName() ) && method.getReturnType() == m.getReturnType() )
+ {
+ Class<?>[] parms = m.getParameterTypes();
+ if ( parms == null )
+ {
+ continue;
+ }
+
+ Class<?>[] mparms = method.getParameterTypes();
+ if ( mparms == null || mparms.length != parms.length )
+ {
+ continue;
+ }
+
+ boolean parmsMatch = true;
+ for ( int p = 0; p < parms.length; p++ )
+ {
+ if ( parms[p] != mparms[p] )
+ {
+ parmsMatch = false;
+ break;
+ }
+ }
+
+ if ( !parmsMatch )
+ {
+ continue;
+ }
+
+ Class<?>[] exceptions = m.getExceptionTypes();
+ if ( exceptions == null )
+ {
+ continue;
+ }
+
+ Class<?>[] mexceptions = method.getExceptionTypes();
+ if ( mexceptions == null || mexceptions.length != exceptions.length )
+ {
+ continue;
+ }
+
+ boolean exceptionsMatch = true;
+ for ( int e = 0; e < exceptions.length; e++ )
+ {
+ if ( exceptions[e] != mexceptions[e] )
+ {
+ exceptionsMatch = false;
+ break;
+ }
+ }
+
+ if ( !exceptionsMatch )
+ {
+ continue;
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Class<?> getInterfaceClass( Class<?> clazz )
+ {
+ if ( "java.util.AbstractList$Itr".equals( clazz.getName() ) )
+ {
+ return Iterator.class;
+ }
+
+ if ( Modifier.isPublic( clazz.getModifiers() ) && clazz.isInterface() || clazz.isPrimitive() )
+ {
+ return clazz;
+ }
+
+ Class<?>[] intf = clazz.getInterfaces();
+
+ for ( Class<?> anIntf : intf )
+ {
+ if ( List.class.isAssignableFrom( anIntf ) )
+ {
+ return List.class;
+ }
+ if ( Iterator.class.isAssignableFrom( anIntf ) )
+ {
+ return Iterator.class;
+ }
+ if ( Map.class.isAssignableFrom( anIntf ) )
+ {
+ return Map.class;
+ }
+ if ( Set.class.isAssignableFrom( anIntf ) )
+ {
+ return Set.class;
+ }
+ if ( Collection.class.isAssignableFrom( anIntf ) )
+ {
+ return Collection.class;
+ }
+ }
+
+ if ( clazz.getSuperclass() != null && clazz.getSuperclass().getInterfaces().length > 0 )
+ {
+ return getInterfaceClass( clazz.getSuperclass() );
+ }
+
+ return clazz;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Class<?> getRootExpressionClass( Node rootNode, OgnlContext context )
+ {
+ if ( context.getRoot() == null )
+ {
+ return null;
+ }
+
+ Class<?> ret = context.getRoot().getClass();
+
+ if ( context.getFirstAccessor() != null && context.getFirstAccessor().isInstance( context.getRoot() ) )
+ {
+ ret = context.getFirstAccessor();
+ }
+
+ return ret;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void compileExpression( OgnlContext context, Node expression, Object root )
+ throws Exception
+ {
+ // System.out.println("Compiling expr class " + expression.getClass().getName() + " and root " + root);
+
+ if ( expression.getAccessor() != null )
+ {
+ return;
+ }
+
+ String getBody, setBody;
+
+ EnhancedClassLoader loader = getClassLoader( context );
+ ClassPool classPool = getClassPool( context, loader );
+
+ CtClass newClass = classPool.makeClass(
+ expression.getClass().getName() + expression.hashCode() + classCounter++ + "Accessor" );
+ newClass.addInterface( getCtClass( ExpressionAccessor.class ) );
+
+ CtClass ognlClass = getCtClass( OgnlContext.class );
+ CtClass objClass = getCtClass( Object.class );
+
+ CtMethod valueGetter = new CtMethod( objClass, "get", new CtClass[] { ognlClass, objClass }, newClass );
+ CtMethod valueSetter =
+ new CtMethod( CtClass.voidType, "set", new CtClass[] { ognlClass, objClass, objClass }, newClass );
+
+ CtField nodeMember = null; // will only be set if uncompilable exception is thrown
+
+ CtClass nodeClass = getCtClass( Node.class );
+ CtMethod setExpression = null;
+
+ try
+ {
+
+ getBody = generateGetter( context, newClass, objClass, classPool, valueGetter, expression, root );
+
+ }
+ catch ( UnsupportedCompilationException uc )
+ {
+ nodeMember = new CtField( nodeClass, "_node", newClass );
+ newClass.addField( nodeMember );
+
+ getBody = generateOgnlGetter( newClass, valueGetter, nodeMember );
+
+ setExpression = CtNewMethod.setter( "setExpression", nodeMember );
+ newClass.addMethod( setExpression );
+ }
+
+ try
+ {
+
+ setBody = generateSetter( context, newClass, objClass, classPool, valueSetter, expression, root );
+
+ }
+ catch ( UnsupportedCompilationException uc )
+ {
+ if ( nodeMember == null )
+ {
+ nodeMember = new CtField( nodeClass, "_node", newClass );
+ newClass.addField( nodeMember );
+ }
+
+ setBody = generateOgnlSetter( newClass, valueSetter, nodeMember );
+
+ if ( setExpression == null )
+ {
+ setExpression = CtNewMethod.setter( "setExpression", nodeMember );
+ newClass.addMethod( setExpression );
+ }
+ }
+
+ try
+ {
+ newClass.addConstructor( CtNewConstructor.defaultConstructor( newClass ) );
+
+ Class<?> clazz = classPool.toClass( newClass );
+ newClass.detach();
+
+ expression.setAccessor( (ExpressionAccessor) clazz.newInstance() );
+
+ // need to set expression on node if the field was just defined.
+
+ if ( nodeMember != null )
+ {
+ expression.getAccessor().setExpression( expression );
+ }
+
+ }
+ catch ( Throwable t )
+ {
+ throw new RuntimeException( "Error compiling expression on object " + root + " with expression node "
+ + expression + " getter body: " + getBody + " setter body: " + setBody, t );
+ }
+
+ }
+
+ protected String generateGetter( OgnlContext context, CtClass newClass, CtClass objClass, ClassPool classPool,
+ CtMethod valueGetter, Node expression, Object root )
+ throws Exception
+ {
+ String pre = "";
+ String post = "";
+ String body;
+
+ context.setRoot( root );
+
+ // the ExpressionAccessor API has to reference the generic Object class for get/set operations, so this sets up
+ // that known
+ // type beforehand
+
+ context.remove( PRE_CAST );
+
+ // Recursively generate the java source code representation of the top level expression
+
+ String getterCode = expression.toGetSourceString( context, root );
+
+ if ( getterCode == null || getterCode.trim().isEmpty()
+ && !ASTVarRef.class.isAssignableFrom( expression.getClass() ) )
+ {
+ getterCode = "null";
+ }
+
+ String castExpression = (String) context.get( PRE_CAST );
+
+ if ( context.getCurrentType() == null || context.getCurrentType().isPrimitive()
+ || Character.class.isAssignableFrom( context.getCurrentType() )
+ || Object.class == context.getCurrentType() )
+ {
+ pre = pre + " ($w) (";
+ post = post + ")";
+ }
+
+ String rootExpr = !"null".equals( getterCode ) ? getRootExpression( expression, root, context ) : "";
+
+ String noRoot = (String) context.remove( "_noRoot" );
+ if ( noRoot != null )
+ {
+ rootExpr = "";
+ }
+
+ createLocalReferences( context, classPool, newClass, objClass, valueGetter.getParameterTypes() );
+
+ if ( expression instanceof OrderedReturn
+ && ( (OrderedReturn) expression ).getLastExpression() != null )
+ {
+ body = "{ " + ( expression instanceof ASTMethod || expression instanceof ASTChain
+ ? rootExpr
+ : "" ) + ( castExpression != null ? castExpression : "" )
+ + ( (OrderedReturn) expression ).getCoreExpression() + " return " + pre
+ + ( (OrderedReturn) expression ).getLastExpression() + post + ";}";
+
+ }
+ else
+ {
+
+ body =
+ "{ return " + pre + ( castExpression != null ? castExpression : "" ) + rootExpr + getterCode + post
+ + ";}";
+ }
+
+ body = body.replaceAll( "\\.\\.", "." );
+
+ // System.out.println("Getter Body: ===================================\n" + body);
+ valueGetter.setBody( body );
+ newClass.addMethod( valueGetter );
+
+ return body;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String createLocalReference( OgnlContext context, String expression, Class<?> type )
+ {
+ String referenceName = "ref" + context.incrementLocalReferenceCounter();
+ context.addLocalReference( referenceName, new LocalReferenceImpl( referenceName, expression, type ) );
+
+ String castString = "";
+ if ( !type.isPrimitive() )
+ {
+ castString = "(" + ExpressionCompiler.getCastString( type ) + ") ";
+ }
+
+ return castString + referenceName + "($$)";
+ }
+
+ void createLocalReferences( OgnlContext context, ClassPool classPool, CtClass clazz, CtClass unused,
+ CtClass[] params )
+ throws NotFoundException, CannotCompileException
+ {
+ Map<String, LocalReference> referenceMap = context.getLocalReferences();
+ if ( referenceMap == null || referenceMap.isEmpty() )
+ {
+ return;
+ }
+
+ Iterator<LocalReference> it = referenceMap.values().iterator();
+ while( it.hasNext() )
+ {
+ LocalReference ref = it.next();
+ String widener = ref.getType().isPrimitive() ? " " : " ($w) ";
+
+ String body = format( "{ return %s %s; }", widener, ref.getExpression() ).replaceAll( "\\.\\.", "." );
+
+ // System.out.println("adding method " + ref.getName() + " with body:\n" + body + " and return type: " +
+ // ref.getType());
+
+ CtMethod method =
+ new CtMethod( classPool.get( getCastString( ref.getType() ) ), ref.getName(), params, clazz );
+ method.setBody( body );
+
+ clazz.addMethod( method );
+ it.remove();
+ }
+ }
+
+ protected String generateSetter( OgnlContext context, CtClass newClass, CtClass objClass, ClassPool classPool,
+ CtMethod valueSetter, Node expression, Object root )
+ throws Exception
+ {
+ if ( expression instanceof ExpressionNode || expression instanceof ASTConst)
+ {
+ throw new UnsupportedCompilationException( "Can't compile expression/constant setters." );
+ }
+
+ context.setRoot( root );
+ context.remove( PRE_CAST );
+
+ String body;
+
+ String setterCode = expression.toSetSourceString( context, root );
+ String castExpression = (String) context.get( PRE_CAST );
+
+ if ( setterCode == null || setterCode.trim().length() < 1 )
+ {
+ throw new UnsupportedCompilationException( "Can't compile null setter body." );
+ }
+
+ if ( root == null )
+ {
+ throw new UnsupportedCompilationException( "Can't compile setters with a null root object." );
+ }
+
+ String pre = getRootExpression( expression, root, context );
+
+ String noRoot = (String) context.remove( "_noRoot" );
+ if ( noRoot != null )
+ {
+ pre = "";
+ }
+
+ createLocalReferences( context, classPool, newClass, objClass, valueSetter.getParameterTypes() );
+
+ body = "{" + ( castExpression != null ? castExpression : "" ) + pre + setterCode + ";}";
+
+ body = body.replaceAll( "\\.\\.", "." );
+
+ // System.out.println("Setter Body: ===================================\n" + body);
+
+ valueSetter.setBody( body );
+ newClass.addMethod( valueSetter );
+
+ return body;
+ }
+
+ /**
+ * Fail safe getter creation when normal compilation fails.
+ *
+ * @param clazz The javassist class the new method should be attached to.
+ * @param valueGetter The method definition the generated code will be contained within.
+ * @param node The root expression node.
+ * @return The generated source string for this method, the method will still be added via the javassist API either
+ * way so this is really a convenience for exception reporting / debugging.
+ * @throws Exception If a javassist error occurs.
+ */
+ protected String generateOgnlGetter( CtClass clazz, CtMethod valueGetter, CtField node )
+ throws Exception
+ {
+ String body = "return " + node.getName() + ".getValue($1, $2);";
+
+ valueGetter.setBody( body );
+ clazz.addMethod( valueGetter );
+
+ return body;
+ }
+
+ /**
+ * Fail safe setter creation when normal compilation fails.
+ *
+ * @param clazz The javassist class the new method should be attached to.
+ * @param valueSetter The method definition the generated code will be contained within.
+ * @param node The root expression node.
+ * @return The generated source string for this method, the method will still be added via the javassist API either
+ * way so this is really a convenience for exception reporting / debugging.
+ * @throws Exception If a javassist error occurs.
+ */
+ protected String generateOgnlSetter( CtClass clazz, CtMethod valueSetter, CtField node )
+ throws Exception
+ {
+ String body = node.getName() + ".setValue($1, $2, $3);";
+
+ valueSetter.setBody( body );
+ clazz.addMethod( valueSetter );
+
+ return body;
+ }
+
+ /**
+ * Creates a {@link ClassLoader} instance compatible with the javassist classloader and normal OGNL class resolving
+ * semantics.
+ *
+ * @param context The current execution context.
+ * @return The created {@link ClassLoader} instance.
+ */
+ protected EnhancedClassLoader getClassLoader( OgnlContext context )
+ {
+ EnhancedClassLoader ret = loaders.get( context.getClassResolver() );
+
+ if ( ret != null )
+ {
+ return ret;
+ }
+
+ ClassLoader classLoader = new ContextClassLoader( OgnlContext.class.getClassLoader(), context );
+
+ ret = new EnhancedClassLoader( classLoader );
+ loaders.put( context.getClassResolver(), ret );
+
+ return ret;
+ }
+
+ /**
+ * Loads a new class definition via javassist for the specified class.
+ *
+ * @param searchClass The class to load.
+ * @return The javassist class equivalent.
+ * @throws javassist.NotFoundException When the class definition can't be found.
+ */
+ protected CtClass getCtClass( Class<?> searchClass )
+ throws NotFoundException
+ {
+ return pool.get( searchClass.getName() );
+ }
+
+ /**
+ * Gets either a new or existing {@link ClassPool} for use in compiling javassist classes. A new class path object
+ * is inserted in to the returned {@link ClassPool} using the passed in <code>loader</code> instance if a new pool
+ * needs to be created.
+ *
+ * @param context The current execution context.
+ * @param loader The {@link ClassLoader} instance to use - as returned by
+ * {@link #getClassLoader(org.apache.commons.ognl.OgnlContext)}.
+ * @return The existing or new {@link ClassPool} instance.
+ */
+ protected ClassPool getClassPool( OgnlContext context, EnhancedClassLoader loader )
+ {
+ if ( pool != null )
+ {
+ return pool;
+ }
+
+ pool = ClassPool.getDefault();
+ pool.insertClassPath( new LoaderClassPath( loader.getParent() ) );
+
+ return pool;
+ }
+}
diff --git a/src/main/java/org/apache/commons/ognl/enhance/LocalReference.java b/src/main/java/org/apache/commons/ognl/enhance/LocalReference.java
index 57a9be3..a9c18cd 100644
--- a/src/main/java/org/apache/commons/ognl/enhance/LocalReference.java
+++ b/src/main/java/org/apache/commons/ognl/enhance/LocalReference.java
@@ -1,48 +1,48 @@
-package org.apache.commons.ognl.enhance;
-
-/*
- * 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.
- */
-
-/**
- * Container class for {@link OgnlExpressionCompiler} generated local method block references.
- */
-public interface LocalReference
-{
-
- /**
- * The name of the assigned variable reference.
- *
- * @return The name of the reference as it will be when compiled.
- */
- String getName();
-
- /**
- * The expression that sets the value, ie the part after <code><class type> refName = <expression></code>.
- *
- * @return The setting expression.
- */
- String getExpression();
-
- /**
- * The type of reference.
- *
- * @return The type.
- */
- Class<?> getType();
-}
+/*
+ * 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.commons.ognl.enhance;
+
+/**
+ * Container class for {@link OgnlExpressionCompiler} generated local method block references.
+ */
+public interface LocalReference
+{
+
+ /**
+ * The name of the assigned variable reference.
+ *
+ * @return The name of the reference as it will be when compiled.
+ */
+ String getName();
+
+ /**
+ * The expression that sets the value, ie the part after <code><class type> refName = <expression></code>.
+ *
+ * @return The setting expression.
+ */
+ String getExpression();
+
+ /**
+ * The type of reference.
+ *
+ * @return The type.
+ */
+ Class<?> getType();
+}
diff --git a/src/main/java/org/apache/commons/ognl/enhance/LocalReferenceImpl.java b/src/main/java/org/apache/commons/ognl/enhance/LocalReferenceImpl.java
index 0ebddd3..cb078bb 100644
--- a/src/main/java/org/apache/commons/ognl/enhance/LocalReferenceImpl.java
+++ b/src/main/java/org/apache/commons/ognl/enhance/LocalReferenceImpl.java
@@ -1,121 +1,121 @@
-package org.apache.commons.ognl.enhance;
-
-/*
- * 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.
- */
-
-/**
- * Implementation of {@link LocalReference}.
- */
-public class LocalReferenceImpl
- implements LocalReference
-{
-
- private final String name;
-
- private final Class<?> type;
-
- private final String expression;
-
- public LocalReferenceImpl( String name, String expression, Class<?> type )
- {
- this.name = name;
- this.type = type;
- this.expression = expression;
- }
-
- /**
- * {@inheritDoc}
- */
- public String getName()
- {
- return name;
- }
-
- /**
- * {@inheritDoc}
- */
- public String getExpression()
- {
- return expression;
- }
-
- /**
- * {@inheritDoc}
- */
- public Class<?> getType()
- {
- return type;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals( Object o )
- {
- if ( this == o )
- {
- return true;
- }
- if ( o == null || getClass() != o.getClass() )
- {
- return false;
- }
-
- LocalReferenceImpl that = (LocalReferenceImpl) o;
-
- if ( expression != null ? !expression.equals( that.expression ) : that.expression != null )
- {
- return false;
- }
- if ( name != null ? !name.equals( that.name ) : that.name != null )
- {
- return false;
- }
- if ( type != null ? !type.equals( that.type ) : that.type != null )
- {
- return false;
- }
-
- return true;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode()
- {
- int result;
- result = ( name != null ? name.hashCode() : 0 );
- result = 31 * result + ( type != null ? type.hashCode() : 0 );
- result = 31 * result + ( expression != null ? expression.hashCode() : 0 );
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString()
- {
- return "LocalReferenceImpl[" + "_name='" + name + '\'' + '\n' + ", _type=" + type + '\n' + ", _expression='"
- + expression + '\'' + '\n' + ']';
- }
-}
+/*
+ * 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.commons.ognl.enhance;
+
+/**
+ * Implementation of {@link LocalReference}.
+ */
+public class LocalReferenceImpl
+ implements LocalReference
+{
+
+ private final String name;
+
+ private final Class<?> type;
+
+ private final String expression;
+
+ public LocalReferenceImpl( String name, String expression, Class<?> type )
+ {
+ this.name = name;
+ this.type = type;
+ this.expression = expression;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getExpression()
+ {
+ return expression;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Class<?> getType()
+ {
+ return type;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o )
+ {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() )
+ {
+ return false;
+ }
+
+ LocalReferenceImpl that = (LocalReferenceImpl) o;
+
+ if ( expression != null ? !expression.equals( that.expression ) : that.expression != null )
+ {
+ return false;
+ }
+ if ( name != null ? !name.equals( that.name ) : that.name != null )
+ {
+ return false;
+ }
+ if ( type != null ? !type.equals( that.type ) : that.type != null )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode()
+ {
+ int result;
+ result = ( name != null ? name.hashCode() : 0 );
+ result = 31 * result + ( type != null ? type.hashCode() : 0 );
+ result = 31 * result + ( expression != null ? expression.hashCode() : 0 );
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString()
+ {
+ return "LocalReferenceImpl[" + "_name='" + name + '\'' + '\n' + ", _type=" + type + '\n' + ", _expression='"
+ + expression + '\'' + '\n' + ']';
+ }
+}
diff --git a/src/main/java/org/apache/commons/ognl/enhance/OgnlExpressionCompiler.java b/src/main/java/org/apache/commons/ognl/enhance/OgnlExpressionCompiler.java
index 3ef9255..55b1421 100644
--- a/src/main/java/org/apache/commons/ognl/enhance/OgnlExpressionCompiler.java
+++ b/src/main/java/org/apache/commons/ognl/enhance/OgnlExpressionCompiler.java
@@ -1,125 +1,125 @@
-package org.apache.commons.ognl.enhance;
-
-/*
- * 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.
- */
-
-import org.apache.commons.ognl.Node;
-import org.apache.commons.ognl.OgnlContext;
-
-import java.lang.reflect.Method;
-
-/**
- * Core interface implemented by expression compiler instances.
- */
-public interface OgnlExpressionCompiler
-{
-
- /** Static constant used in conjunction with {@link OgnlContext} to store temporary references. */
- String ROOT_TYPE = "-ognl-root-type";
-
- /**
- * The core method executed to compile a specific expression. It is expected that this expression always return a
- * {@link Node} with a non null {@link org.apache.commons.ognl.Node#getAccessor()} instance - unless an exception is
- * thrown by the method or the statement wasn't compilable in this instance because of missing/null objects in the
- * expression. These instances may in some cases continue to call this compilation method until the expression is
- * resolvable.
- *
- * @param context The context of execution.
- * @param expression The pre-parsed root expression node to compile.
- * @param root The root object for the expression - may be null in many instances so some implementations may exit
- * @throws Exception If an error occurs compiling the expression and no strategy has been implemented to handle
- * incremental expression compilation for incomplete expression members.
- */
- void compileExpression( OgnlContext context, Node expression, Object root )
- throws Exception;
-
- /**
- * Gets a javassist safe class string for the given class instance. This is especially useful for handling array vs.
- * normal class casting strings.
- *
- * @param clazz The class to get a string equivalent javassist compatible string reference for.
- * @return The string equivalent of the class.
- */
- String getClassName( Class<?> clazz );
-
- /**
- * Used in places where the preferred {@link #getSuperOrInterfaceClass(java.lang.reflect.Method, Class)} isn't
- * possible because the method isn't known for a class. Attempts to upcast the given class to the next available
- * non-private accessible class so that compiled expressions can reference the interface class of an instance so as
- * not to be compiled in to overly specific statements.
- *
- * @param clazz The class to attempt to find a compatible interface for.
- * @return The same class if no higher level interface could be matched against or the interface equivalent class.
- */
- Class<?> getInterfaceClass( Class<?> clazz );
-
- /**
- * For the given {@link Method} and class finds the highest level interface class this combination can be cast to.
- *
- * @param m The method the class must implement.
- * @param clazz The current class being worked with.
- * @return The highest level interface / class that the referenced {@link Method} is declared in.
- */
- Class<?> getSuperOrInterfaceClass( Method m, Class<?> clazz );
-
- /**
- * For a given root object type returns the base class type to be used in root referenced expressions. This helps in
- * some instances where the root objects themselves are compiled javassist instances that need more generic class
- * equivalents to cast to.
- *
- * @param rootNode The root expression node.
- * @param context The current execution context.
- * @return The root expression class type to cast to for this node.
- */
- Class<?> getRootExpressionClass( Node rootNode, OgnlContext context );
-
- /**
- * Used primarily by AST types like {@link org.apache.commons.ognl.ASTChain} where <code>foo.bar.id</code> type
- * references may need to be cast multiple times in order to properly resolve the members in a compiled statement.
- * <p>
- * This method should be using the various {@link org.apache.commons.ognl.OgnlContext#getCurrentType()} /
- * {@link org.apache.commons.ognl.OgnlContext#getCurrentAccessor()} methods to inspect the type stack and properly
- * cast to the right classes - but only when necessary.
- * </p>
- *
- * @param context The current execution context.
- * @param expression The node being checked for casting.
- * @param body The java source string generated by the given node.
- * @return The body string parameter plus any additional casting syntax needed to make the expression resolvable.
- */
- String castExpression( OgnlContext context, Node expression, String body );
-
- /**
- * Method is used for expressions where multiple inner parameter method calls in generated java source strings cause
- * javassit failures. It is hacky and cumbersome to have to generate expressions this way but it's the only current
- * known way to make javassist happy.
- * <p>
- * Takes an expression block generated by a node and creates a new method on the base object being compiled so that
- * sufficiently complicated sub expression blocks can be broken out in to distinct methods to be referenced by the
- * core accessor / setter methods in the base compiled root object.
- * </p>
- *
- * @param context The current execution context.
- * @param expression The java source expression to dump in to a seperate method reference.
- * @param type The return type that should be specified for the new method.
- * @return The method name that will be used to reference the sub expression in place of the actual sub expression
- * itself.
- */
- String createLocalReference( OgnlContext context, String expression, Class<?> type );
-}
+/*
+ * 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.commons.ognl.enhance;
+
+import org.apache.commons.ognl.Node;
+import org.apache.commons.ognl.OgnlContext;
+
+import java.lang.reflect.Method;
+
+/**
+ * Core interface implemented by expression compiler instances.
+ */
+public interface OgnlExpressionCompiler
+{
+
+ /** Static constant used in conjunction with {@link OgnlContext} to store temporary references. */
+ String ROOT_TYPE = "-ognl-root-type";
+
+ /**
+ * The core method executed to compile a specific expression. It is expected that this expression always return a
+ * {@link Node} with a non null {@link org.apache.commons.ognl.Node#getAccessor()} instance - unless an exception is
+ * thrown by the method or the statement wasn't compilable in this instance because of missing/null objects in the
+ * expression. These instances may in some cases continue to call this compilation method until the expression is
+ * resolvable.
+ *
+ * @param context The context of execution.
+ * @param expression The pre-parsed root expression node to compile.
+ * @param root The root object for the expression - may be null in many instances so some implementations may exit
+ * @throws Exception If an error occurs compiling the expression and no strategy has been implemented to handle
+ * incremental expression compilation for incomplete expression members.
+ */
+ void compileExpression( OgnlContext context, Node expression, Object root )
+ throws Exception;
+
+ /**
+ * Gets a javassist safe class string for the given class instance. This is especially useful for handling array vs.
+ * normal class casting strings.
+ *
+ * @param clazz The class to get a string equivalent javassist compatible string reference for.
+ * @return The string equivalent of the class.
+ */
+ String getClassName( Class<?> clazz );
+
+ /**
+ * Used in places where the preferred {@link #getSuperOrInterfaceClass(java.lang.reflect.Method, Class)} isn't
+ * possible because the method isn't known for a class. Attempts to upcast the given class to the next available
+ * non-private accessible class so that compiled expressions can reference the interface class of an instance so as
+ * not to be compiled in to overly specific statements.
+ *
+ * @param clazz The class to attempt to find a compatible interface for.
+ * @return The same class if no higher level interface could be matched against or the interface equivalent class.
+ */
+ Class<?> getInterfaceClass( Class<?> clazz );
+
+ /**
+ * For the given {@link Method} and class finds the highest level interface class this combination can be cast to.
+ *
+ * @param m The method the class must implement.
+ * @param clazz The current class being worked with.
+ * @return The highest level interface / class that the referenced {@link Method} is declared in.
+ */
+ Class<?> getSuperOrInterfaceClass( Method m, Class<?> clazz );
+
+ /**
+ * For a given root object type returns the base class type to be used in root referenced expressions. This helps in
+ * some instances where the root objects themselves are compiled javassist instances that need more generic class
+ * equivalents to cast to.
+ *
+ * @param rootNode The root expression node.
+ * @param context The current execution context.
+ * @return The root expression class type to cast to for this node.
+ */
+ Class<?> getRootExpressionClass( Node rootNode, OgnlContext context );
+
+ /**
+ * Used primarily by AST types like {@link org.apache.commons.ognl.ASTChain} where <code>foo.bar.id</code> type
+ * references may need to be cast multiple times in order to properly resolve the members in a compiled statement.
+ * <p>
+ * This method should be using the various {@link org.apache.commons.ognl.OgnlContext#getCurrentType()} /
+ * {@link org.apache.commons.ognl.OgnlContext#getCurrentAccessor()} methods to inspect the type stack and properly
+ * cast to the right classes - but only when necessary.
+ * </p>
+ *
+ * @param context The current execution context.
+ * @param expression The node being checked for casting.
+ * @param body The java source string generated by the given node.
+ * @return The body string parameter plus any additional casting syntax needed to make the expression resolvable.
+ */
+ String castExpression( OgnlContext context, Node expression, String body );
+
+ /**
+ * Method is used for expressions where multiple inner parameter method calls in generated java source strings cause
+ * javassit failures. It is hacky and cumbersome to have to generate expressions this way but it's the only current
+ * known way to make javassist happy.
+ * <p>
+ * Takes an expression block generated by a node and creates a new method on the base object being compiled so that
+ * sufficiently complicated sub expression blocks can be broken out in to distinct methods to be referenced by the
+ * core accessor / setter methods in the base compiled root object.
+ * </p>
+ *
+ * @param context The current execution context.
+ * @param expression The java source expression to dump in to a seperate method reference.
+ * @param type The return type that should be specified for the new method.
+ * @return The method name that will be used to reference the sub expression in place of the actual sub expression
+ * itself.
+ */
+ String createLocalReference( OgnlContext context, String expression, Class<?> type );
+}
diff --git a/src/main/java/org/apache/commons/ognl/enhance/OrderedReturn.java b/src/main/java/org/apache/commons/ognl/enhance/OrderedReturn.java
index 70ee790..56b91ad 100644
--- a/src/main/java/org/apache/commons/ognl/enhance/OrderedReturn.java
+++ b/src/main/java/org/apache/commons/ognl/enhance/OrderedReturn.java
@@ -1,44 +1,43 @@
-package org.apache.commons.ognl.enhance;
-
-/*
- * 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.
- */
-
-
-/**
- * Marks an ognl expression {@link org.apache.commons.ognl.Node} as needing to have the return portion of a getter
- * method happen in a specific
- * part of the generated expression vs just having the whole expression returned in one chunk.
- */
-public interface OrderedReturn
-{
-
- /**
- * Get the core expression to execute first before any return foo logic is started.
- *
- * @return The core standalone expression that shouldn't be pre-pended with a return keyword.
- */
- String getCoreExpression();
-
- /**
- * Gets the last expression to be pre-pended with a return <expression> block.
- *
- * @return The expression representing the return portion of a statement;
- */
- String getLastExpression();
-}
+/*
+ * 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.commons.ognl.enhance;
+
+/**
+ * Marks an ognl expression {@link org.apache.commons.ognl.Node} as needing to have the return portion of a getter
+ * method happen in a specific
+ * part of the generated expression vs just having the whole expression returned in one chunk.
+ */
+public interface OrderedReturn
+{
+
+ /**
+ * Get the core expression to execute first before any return foo logic is started.
+ *
+ * @return The core standalone expression that shouldn't be pre-pended with a return keyword.
+ */
+ String getCoreExpression();
+
+ /**
+ * Gets the last expression to be pre-pended with a return <expression> block.
+ *
+ * @return The expression representing the return portion of a statement;
+ */
+ String getLastExpression();
+}
diff --git a/src/main/java/org/apache/commons/ognl/enhance/UnsupportedCompilationException.java b/src/main/java/org/apache/commons/ognl/enhance/UnsupportedCompilationException.java
index 24f9a72..9639799 100644
--- a/src/main/java/org/apache/commons/ognl/enhance/UnsupportedCompilationException.java
+++ b/src/main/java/org/apache/commons/ognl/enhance/UnsupportedCompilationException.java
@@ -1,48 +1,48 @@
-package org.apache.commons.ognl.enhance;
-
-/*
- * 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.
- */
-
-/**
- * Thrown during bytecode enhancement conversions of ognl expressions to indicate that a certain expression isn't
- * currently supported as a pure java bytecode enhanced version.
- * <p>
- * If this exception is thrown it is expected that ognl will fall back to default ognl evaluation of the expression.
- * </p>
- */
-public class UnsupportedCompilationException
- extends RuntimeException
-{
-
- /**
- *
- */
- private static final long serialVersionUID = 4961625077128174947L;
-
- public UnsupportedCompilationException( String message )
- {
- super( message );
- }
-
- public UnsupportedCompilationException( String message, Throwable cause )
- {
- super( message, cause );
- }
-
-}
+/*
+ * 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.commons.ognl.enhance;
+
+/**
+ * Thrown during bytecode enhancement conversions of ognl expressions to indicate that a certain expression isn't
+ * currently supported as a pure java bytecode enhanced version.
+ * <p>
+ * If this exception is thrown it is expected that ognl will fall back to default ognl evaluation of the expression.
+ * </p>
+ */
+public class UnsupportedCompilationException
+ extends RuntimeException
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 4961625077128174947L;
+
+ public UnsupportedCompilationException( String message )
+ {
+ super( message );
+ }
+
+ public UnsupportedCompilationException( String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/ognl/enhance/package-info.java b/src/main/java/org/apache/commons/ognl/enhance/package-info.java
index e96f047..b3b6099 100644
--- a/src/main/java/org/apache/commons/ognl/enhance/package-info.java
+++ b/src/main/java/org/apache/commons/ognl/enhance/package-info.java
@@ -1,24 +1,24 @@
-package org.apache.commons.ognl.enhance;
-
-/*
- * 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.
- */
-
-/*
- * Enhanced basic Java components.
- */
+/*
+ * 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.commons.ognl.enhance;
+
+/*
+ * Enhanced basic Java components.
+ */