Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   // Copyright 2007, 2008, 2009, 2010 The Apache Software Foundation
   //
   // Licensed under the Apache License, Version 2.0 (the "License");
   // you may not use this file except in compliance with the License.
   // You may obtain a copy of the License at
   //
   // http://www.apache.org/licenses/LICENSE-2.0
   //
   // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  package org.apache.tapestry5.internal.services;
  
  
  import java.util.List;
  import java.util.Locale;
  import java.util.Map;
  
  import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.*;
  
  {
      private static final MethodSignature GET_SIGNATURE = new MethodSignature(Object.class"get"new Class[]
      { Object.class }, null);
  
      private static final MethodSignature SET_SIGNATURE = new MethodSignature(void.class"set"new Class[]
      { Object.classObject.class }, null);
  
      private static final Method RANGE;
  
      private static final Method INVERT;
  
      static
      {
          try
          {
               = BasePropertyConduit.class.getMethod("range"int.classint.class);
               = BasePropertyConduit.class.getMethod("invert"Object.class);
          }
          catch (NoSuchMethodException ex)
          {
              throw new RuntimeException(ex);
          }
      }
  
      private final AnnotationProvider nullAnnotationProvider = new NullAnnotationProvider();
  
      private static class ConstructorParameter
      {
          private final String fieldName;
  
          private final Class type;
  
          private final Object value;
  
          ConstructorParameter(String fieldNameClass typeObject value)
          {
              this. = fieldName;
              this. = type;
              this. = value;
          }
  
          public String getFieldName()
          {
              return ;
          }
  
          public Class getType()
         {
             return ;
         }
 
         public Object getValue()
         {
             return ;
         }
     }

    
Describes all the gory details of one term (one property or method invocation) from within the expression.
 
     private interface ExpressionTermInfo extends AnnotationProvider
     {

        
The method to invoke to read the property value, or null.
 
         Method getReadMethod();

        
The method to invoke to write the property value, or null. Always null for method terms (which are inherently read-only).
 
         Method getWriteMethod();

        
The return type of the method, or the type of the property.
 
         Class getType();

        
True if an explicit cast to the return type is needed (typically because of generics).
 
         boolean isCastRequired();

        
Returns a user-presentable name identifying the property or method name.
 
         String getDescription();

        
Returns the name of the property, if exists. This is also the name of the public field.
 
         String getPropertyName();

        
Returns true if the term is actually a public field.
 
         boolean isField();

        
Returns the Field if the term is a public field.
 
         Field getField();
 
     }

    
How are null values in intermdiate terms to be handled?
 
     private enum NullHandling
     {
        
Add code to check for null and throw exception if null.
 
         FORBID,

        
Add code to check for null and short-circuit (i.e., the "?." safe-dereference operator)
 
         ALLOW,

        
Add no null check at all.
 
         IGNORE
     }
 
     private class GeneratedTerm
     {
         final Type type;
 
         final String termReference;

        

Parameters:
type type of variable
termReference name of variable, or a constant value
 
         private GeneratedTerm(Type typeString termReference)
         {
             this. = type;
             this. = termReference;
         }
     }
 
     private final PropertyAccess access;
 
     private final ClassFactory classFactory;
 
     private final TypeCoercer typeCoercer;
 
     private final StringInterner interner;

    
Because of stuff like Hibernate, we sometimes start with a subclass in some inaccessible class loader and need to work up to a base class from a common class loader.
 
     private final Map<ClassClassclassToEffectiveClass = CollectionFactory.newConcurrentMap();

    
Keyed on combination of root class and expression.
 
     private final Map<MultiKeyPropertyConduitcache = CollectionFactory.newConcurrentMap();
 
     private final Invariant invariantAnnotation = new Invariant()
     {
         public Class<? extends AnnotationannotationType()
         {
             return Invariant.class;
         }
     };
 
     {
         public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
         {
             if (annotationClass == Invariant.class)
                 return annotationClass.cast();
 
             return null;
         }
     };
 
     private final PropertyConduit literalTrue;
 
     private final PropertyConduit literalFalse;
 
     private final PropertyConduit literalNull;

    
Encapsulates the process of building a PropertyConduit instance from an expression.
 
     class PropertyConduitBuilder
     {
         private final Class rootType;
 
         private final ClassFab classFab;
 
         private final String expression;
 
         private final Tree tree;
 
         private Class conduitPropertyType;
 
         private String conduitPropertyName;
 
 
         // Used to create unique variable names.
 
         private int variableIndex = 0;
 
         private final List<ConstructorParameterparameters = CollectionFactory.newList();
 
         private final BodyBuilder navBuilder = new BodyBuilder();
 
         PropertyConduitBuilder(Class rootTypeString expressionTree tree)
         {
             this. = rootType;
             this. = expression;
             this. = tree;
 
             String name = ClassFabUtils.generateClassName("PropertyConduit");
 
             this. = .newClass(nameBasePropertyConduit.class);
         }
 
         PropertyConduit createInstance()
         {
             createAccessors();
 
             Object[] parameters = createConstructor();
 
             Class conduitClass = .createClass();
 
             try
             {
                 return (PropertyConduitconduitClass.getConstructors()[0].newInstance(parameters);
             }
             catch (Exception ex)
             {
                 throw new RuntimeException(ex);
             }
         }
 
         private Object[] createConstructor()
         {
             List<Classtypes = CollectionFactory.newList();
 
             // $1, $2, $3, $4, $5 ...
 
             types.add(Class.class);
             types.add(String.class);
             types.add(AnnotationProvider.class);
             types.add(String.class);
             types.add(TypeCoercer.class);
 
             List<Objectvalues = CollectionFactory.newList();
 
             values.add();
             values.add();
             values.add();
             values.add(.format("PropertyConduit[%s %s]".getName(), ));
             values.add();
 
             BodyBuilder builder = new BodyBuilder().begin();
 
             builder.addln("super($1,$2,$3,$4,$5);");
 
             int index = 6;
 
             for (ConstructorParameter p : )
             {
                 types.add(p.getType());
                 values.add(p.getValue());
 
                 builder.addln("%s = $%d;"p.getFieldName(), index++);
             }
 
             builder.end();
 
             Class[] arrayOfTypes = types.toArray(new Class[0]);
 
             .addConstructor(arrayOfTypesnullbuilder.toString());
 
             return values.toArray();
         }
 
         private String addInjection(Class fieldTypeObject fieldValue)
         {
             String fieldName = String.format("injected_%s_%d"toSimpleName(fieldType), .size());
 
             .addField(fieldName. | .fieldType);
 
             .add(new ConstructorParameter(fieldNamefieldTypefieldValue));
 
             return fieldName;
         }
 
         private void createNoOp(ClassFab classFabMethodSignature signatureString formatObject... values)
         {
             String message = String.format(formatvalues);
 
             String body = String.format("throw new RuntimeException(\"%s\");"message);
 
             classFab.addMethod(.signaturebody);
         }
 
         private boolean isLeaf(Tree node)
         {
             int type = node.getType();
 
             return type !=  && type != ;
         }
 
         private void createGetRoot()
         {
             BodyBuilder builder = new BodyBuilder().begin();
 
             builder.addln("%s root = (%<s) $1;", ClassFabUtils.toJavaClassName());
 
             builder.addln(
                     "if (root == null) throw new NullPointerException(\"Root object of property expression '%s' is null.\");",
                     );
 
             builder.addln("return root;");
 
             builder.end();
 
             MethodSignature sig = new MethodSignature("getRoot"new Class[]
             { Object.class }, null);
 
             .addMethod(.sigbuilder.toString());
         }
 
         private void addRootVariable(BodyBuilder builder)
         {
             builder.addln("%s root = getRoot($1);", ClassFabUtils.toJavaClassName());
         }
 
         private void createAccessors()
         {
             createGetRoot();
 
             .begin();
 
             String previousReference = "$1";
             Type activeType = ;
 
             Tree node = ;
 
             while (!isLeaf(node))
             {
                 GeneratedTerm term = processDerefNode(activeTypenodepreviousReference"$1");
 
                 activeType = term.type;
 
                 previousReference = term.termReference;
 
                 // Second term is the continuation, possibly another chained
                 // DEREF, etc.
                 node = node.getChild(1);
             }
 
             .addln("return %s;"previousReference);
 
             .end();
             Class activeClass = GenericsUtils.asClass(activeType);
 
             MethodSignature sig = new MethodSignature(activeClass"navigate"new Class[]
             {  }, null);
 
             .addMethod(.sig.toString());
 
             createGetterAndSetter(activeClasssignode);
         }
 
         private void createGetterAndSetter(Class activeTypeMethodSignature navigateMethodTree node)
         {
             switch (node.getType())
             {
                 case :
                 case :
 
                     // So, a this point, we have the navigation method written
                     // and it covers all but the terminal
                     // de-reference. node is an IDENTIFIER or INVOKE. We're
                     // ready to use the navigation
                     // method to implement get() and set().
 
                     ExpressionTermInfo info = infoForMember(activeTypenode);
 
                     createSetter(navigateMethodinfo);
                     createGetter(navigateMethodnodeinfo);
 
                      = info.getType();
                      = info.getPropertyName();
                      = info;
 
                     return;
 
                 case :
 
                     // As currently implemented, RANGEOP can only appear as the
                     // top level, which
                     // means we didn't need the navigate method after all.
 
                     createRangeOpGetter(node"root");
                     createNoOpSetter();
 
                      = IntegerRange.class;
 
                     return;
 
                 case :
 
                     createListGetter(node"root");
                     createNoOpSetter();
 
                      = List.class;
 
                     return;
 
                 case :
                     createNotOpGetter(node"root");
                     createNoOpSetter();
 
                      = boolean.class;
 
                     return;
 
                 default:
                     throw unexpectedNodeType(node);
             }
         }
 
         private void createRangeOpGetter(Tree nodeString rootName)
         {
             BodyBuilder builder = new BodyBuilder().begin();
 
             addRootVariable(builder);
 
             builder.addln("return %s;"createMethodInvocation(buildernoderootName, 0, ));
 
             builder.end();
 
             .addMethod(.builder.toString());
         }
 
         private void createNotOpGetter(Tree nodeString rootName)
         {
             BodyBuilder builder = new BodyBuilder().begin();
 
             addRootVariable(builder);
 
             builder.addln("return ($w) %s;"createMethodInvocation(buildernoderootName, 0, ));
 
             builder.end();
 
             .addMethod(.builder.toString());
         }
 
         public void createListGetter(Tree nodeString rootName)
         {
             BodyBuilder builder = new BodyBuilder().begin();
 
             addRootVariable(builder);
 
             builder.addln("return %s;"createListConstructor(buildernoderootName));
 
             builder.end();
 
             .addMethod(.builder.toString());
         }
 
         private String createListConstructor(BodyBuilder builderTree nodeString rootName)
         {
             String listName = nextVariableName(List.class);
 
             int count = node.getChildCount();
 
             builder.addln("java.util.List %s = new java.util.ArrayList(%d);"listNamecount);
 
             for (int i = 0; i < counti++)
             {
                 GeneratedTerm generatedTerm = subexpression(buildernode.getChild(i), rootName);
 
                 builder.addln("%s.add(($w) %s);"listNamegeneratedTerm.termReference);
             }
 
             return listName;
         }
 
         private String createNotOp(BodyBuilder builderTree nodeString rootName)
         {
             String flagName = nextVariableName(Boolean.class);
             GeneratedTerm term = subexpression(buildernode.getChild(0), rootName);
 
             builder.addln("boolean %s = invert(($w) %s);"flagNameterm.termReference);
 
             return flagName;
         }

        
Evalutates the node as a sub expression, storing the result into a new variable, whose name is returned.

Parameters:
builder to receive generated code
node root of tree of nodes to be evaluated
rootName name of variable holding reference to root object of expression
Returns:
GeneratedTerm identifying the name of the variable and its type
 
         private GeneratedTerm subexpression(BodyBuilder builderTree nodeString rootName)
         {
             String previousReference = rootName;
             Class activeType = ;
 
             while (node != null)
             {
                 switch (node.getType())
                 {
                     case :
                     case :
 
                         previousReference = node.getType() ==  ? "true" : "false";
                         activeType = boolean.class;
 
                         node = null;
                         break;
 
                     case :
 
                         long integerValue = Long.parseLong(node.getText());
 
                         previousReference = String.format("%dL"integerValue);
                         activeType = long.class;
 
                         node = null;
 
                         break;
 
                     case :
 
                         double decimalValue = Double.parseDouble(node.getText());
 
                         previousReference = String.format(."%fd"decimalValue);
                         activeType = double.class;
 
                         node = null;
 
                         break;
 
                     case :
 
                         String stringValue = node.getText();
                         // Injecting is easier; don't have to fuss with escaping
                         // quotes or such.
                         previousReference = addInjection(String.classstringValue);
                         activeType = String.class;
 
                         node = null;
 
                         break;
 
                     case :
                     case :
 
                         GeneratedTerm generated = processDerefNode(builderactiveTypenodepreviousReference,
                                 rootName);
 
                         previousReference = generated.termReference;
                         activeType = GenericsUtils.asClass(generated.type);
 
                         node = node.getChild(1);
 
                         break;
 
                     case :
                     case :
 
                         generated = addAccessForMember(builderactiveTypenodepreviousReferencerootName,
                                 .);
 
                         previousReference = generated.termReference;
                         activeType = GenericsUtils.asClass(generated.type);
 
                         node = null;
 
                         break;
 
                     case :
 
                         previousReference = createNotOp(buildernoderootName);
                         activeType = boolean.class;
 
                         node = null;
 
                         break;
 
                     case :
 
                         previousReference = createListConstructor(buildernoderootName);
                         activeType = List.class;
 
                         node = null;
 
                         break;
 
                     default:
                         throw unexpectedNodeType(node,
                                 );
                 }
             }
 
             return new GeneratedTerm(activeTypepreviousReference);
         }
 
         private void createSetter(MethodSignature navigateMethodExpressionTermInfo info)
         {
             // A write method will only be identified if the info is a writable
             // property.
             // Other alternatives: a method as the final term, or a read-only
             // property.
 
             Method method = info.getWriteMethod();
 
             if (method == null && !info.isField())
             {
                 createNoOpSetter();
                 return;
             }
 
             BodyBuilder builder = new BodyBuilder().begin();
 
             addRootVariable(builder);
 
             builder.addln("%s target = navigate(root);", ClassFabUtils.toJavaClassName(navigateMethod.getReturnType()));
 
             // I.e. due to ?. operator. The navigate method will already have
             // checked for nulls
             // if they are not allowed.
 
             builder.addln("if (target == null) return;");
 
             String propertyTypeName = ClassFabUtils.toJavaClassName(info.getType());
 
             String reference = ClassFabUtils.castReference("$2"propertyTypeName);
 
             if (info.isField())
             {
                 builder.add("target.%s = %s;"info.getPropertyName(), reference);
             }
             else
             {
                 builder.addln("target.%s(%s);"method.getName(), reference);
             }
 
             builder.end();
 
             .addMethod(.builder.toString());
         }
 
         private void createNoOpSetter()
         {
             createNoOp("Expression '%s' for class %s is read-only.",
                     .getName());
         }
 
         private void createGetter(MethodSignature navigateMethodTree nodeExpressionTermInfo info)
         {
             Method method = info.getReadMethod();
 
             if (method == null && !info.isField())
             {
                 createNoOp("Expression %s for class %s is write-only.",
                         .getName());
                 return;
             }
 
             BodyBuilder builder = new BodyBuilder().begin();
 
             addRootVariable(builder);
 
             builder.addln("%s target = navigate(root);", ClassFabUtils.toJavaClassName(navigateMethod.getReturnType()));
 
             // I.e. due to ?. operator. The navigate method will already have
             // checked for nulls
             // if they are not allowed.
 
             builder.addln("if (target == null) return null;");
 
             String reference = info.isField() ? info.getPropertyName() : createMethodInvocation(buildernode"root",
                     method);
 
             builder.addln("return ($w) target.%s;"reference);
 
             builder.end();
 
             .addMethod(.builder.toString());
         }

        
Creates a method invocation call for the given node (an INVOKE node).

Parameters:
bodyBuilder may receive new code to define variables for some sub-expressions
node the INVOKE node; child #1 and up are parameter expressions to the method being invoked
rootName name of variable holding reference to root object of expression
method defines the name and parameter types of the method to invoke
Returns:
method invocation string (the name of the method and any parameters, ready to be added to a method body)
 
         private String createMethodInvocation(BodyBuilder bodyBuilderTree nodeString rootNameMethod method)
         {
             return createMethodInvocation(bodyBuildernoderootName, 1, method);
         }

        
Creates a method invocation call for the given node

Parameters:
bodyBuilder may receive new code to define variables for some sub-expressions
node the node containing child nodes for the parameters
rootName name of variable holding reference to root object of expression
childOffset the offset to the first parameter (for example, this is 1 for an INVOKE node)
method defines the name and parameter types of the method to invoke
Returns:
method invocation string (the name of the method and any parameters, ready to be added to a method body)
 
         private String createMethodInvocation(BodyBuilder bodyBuilderTree nodeString rootNameint childOffset,
                 Method method)
         {
             Class[] parameterTypes = method.getParameterTypes();
 
             StringBuilder builder = new StringBuilder();
 
             builder.append(method.getName());
             builder.append("(");
 
             for (int i = 0; i < parameterTypes.lengthi++)
             {
                 // child(0) is the method name, child(1) is the first parameter,
                 // etc.
 
                 GeneratedTerm generatedTerm = subexpression(bodyBuildernode.getChild(i + childOffset), rootName);
                 String currentReference = generatedTerm.termReference;
 
                 Class actualType = GenericsUtils.asClass(generatedTerm.type);
 
                 Class parameterType = parameterTypes[i];
 
                 boolean needsUnwrap = false;
 
                 if (!parameterType.isAssignableFrom(actualType))
                 {
                     String coerced = nextVariableName(parameterType);
 
                     String call = String.format("coerce(($w) %s, %s)"currentReference,
                             addInjection(Class.classparameterType));
 
                     String parameterTypeName = ClassFabUtils.toJavaClassName(parameterType);
 
                     bodyBuilder.addln("%s %s = %s;"parameterTypeNamecoerced,
                             ClassFabUtils.castReference(callparameterTypeName));
 
                     currentReference = coerced;
                 }
                 else
                 {
                     needsUnwrap = parameterType.isPrimitive() && !actualType.isPrimitive();
                 }
 
                 if (i > 0)
                     builder.append(", ");
 
                 builder.append(currentReference);
 
                 if (needsUnwrap)
                 {
                     builder.append(".").append(ClassFabUtils.getUnwrapMethodName(parameterType)).append("()");
                 }
             }
 
             return builder.append(")").toString();
         }

        
Extends the navigate method for a node, which will be a DEREF or SAFEDERF.
 
         private GeneratedTerm processDerefNode(BodyBuilder builderType activeTypeTree node,
                 String previousVariableNameString rootName)
         {
             // The first child is the term.
 
             Tree term = node.getChild(0);
 
             boolean allowNull = node.getType() == ;
 
             // Returns the type of the method/property ... this is the wrapped
             // (i.e. java.lang.Integer) type if
             // the real type is primitive. It also reflects generics information
             // that may have been associated
             // with the underlying method.
 
             return addAccessForMember(builderactiveTypetermpreviousVariableNamerootName,
                     allowNull ? . : .);
         }
 
         private String nextVariableName(Class type)
         {
             return String.format("var_%s_%d"toSimpleName(type), ++);
         }
 
         private String toSimpleName(Class type)
         {
             if (type.isArray())
             {
                 Class<?> componentType = type.getComponentType();
 
                 while (componentType.isArray())
                 {
                     componentType = componentType.getComponentType();
                 }
 
                 return InternalUtils.lastTerm(componentType.getName()) + "_array";
             }
             return InternalUtils.lastTerm(type.getName());
         }
 
         private GeneratedTerm addAccessForMember(BodyBuilder builderType activeTypeTree term,
                 String previousVariableNameString rootNameNullHandling nullHandling)
         {
             assertNodeType(term);
             Class activeClass = GenericsUtils.asClass(activeType);
             // Get info about this property or method.
 
             ExpressionTermInfo info = infoForMember(activeClassterm);
 
             Method method = info.getReadMethod();
 
             if (method == null && !info.isField())
                 throw new RuntimeException(String.format(
                         "Property '%s' of class %s is not readable (it has no read accessor method).",
                         info.getDescription(), activeClass.getName()));
 
             Type termType;
             /*
              * It's not possible for the ClassPropertyAdapter to know about the generic info for all the properties of
              * a class. For instance; if the type arguments of a field are provided by a subclass.
              */
             if (info.isField())
             {
                 termType = GenericsUtils.extractActualType(activeTypeinfo.getField());
             }
             else
             {
                 termType = GenericsUtils.extractActualType(activeTypemethod);
             }
 
             Class termClass = GenericsUtils.asClass(termType);
 
             final Class wrappedType = ClassFabUtils.getWrapperType(termClass);
 
             String wrapperTypeName = ClassFabUtils.toJavaClassName(wrappedType);
 
             final String variableName = nextVariableName(wrappedType);
 
             String reference = info.isField() ? info.getPropertyName() : createMethodInvocation(builderterm,
                     rootNamemethod);
 
             builder.add("%s %s = "wrapperTypeNamevariableName);
 
             // Casts are needed for primitives, and for the case where
             // generics are involved.
 
             if (termClass.isPrimitive())
             {
                 builder.add(" ($w) ");
             }
             else if (info.isCastRequired() || info.getType() != termClass)
             {
                 builder.add(" (%s) "wrapperTypeName);
             }
 
             builder.addln("%s.%s;"previousVariableNamereference);
 
             switch (nullHandling)
             {
                 case :
                     builder.addln("if (%s == null) return null;"variableName);
                     break;
 
                 case :
                     // Perform a null check on intermediate terms.
                     builder.addln("if (%s == null) %s.nullTerm(\"%s\", \"%s\", $1);"variableName,
                             PropertyConduitSourceImpl.class.getName(), info.getDescription(), );
                     break;
 
                 default:
                     break;
             }
 
             return new GeneratedTerm(wrappedType == termClass ? termType : wrappedTypevariableName);
         }
 
         private void assertNodeType(Tree nodeint... expected)
         {
             int type = node.getType();
 
             for (int e : expected)
             {
                 if (type == e)
                     return;
             }
 
             throw unexpectedNodeType(nodeexpected);
        }
        private RuntimeException unexpectedNodeType(Tree nodeint... expected)
        {
            List<StringtokenNames = CollectionFactory.newList();
            for (int i = 0; i < expected.lengthi++)
                tokenNames.add(.[expected[i]]);
            String message = String.format("Node %s was type %s, but was expected to be (one of) %s.",
                    node.toStringTree(), .[node.getType()],
                    InternalUtils.joinSorted(tokenNames));
            return new RuntimeException(message);
        }
        private ExpressionTermInfo infoForMember(Class activeTypeTree node)
        {
            if (node.getType() == )
                return infoForInvokeNode(activeTypenode);
            return infoForPropertyOrPublicField(activeTypenode);
        }
        private ExpressionTermInfo infoForPropertyOrPublicField(Class activeTypeTree node)
        {
            String propertyName = node.getText();
            ClassPropertyAdapter classAdapter = .getAdapter(activeType);
            final PropertyAdapter adapter = classAdapter.getPropertyAdapter(propertyName);
            if (adapter == null)
            {
                List<Stringnames = classAdapter.getPropertyNames();
                throw new UnknownValueException(String.format(
                        "Class %s does not contain a property (or public field) named '%s'."activeType.getName(),
                        propertyName), new AvailableValues("Properties (and public fields)"names));
            }
            return createExpressionTermInfoForProperty(adapter);
        }
        {
            return new ExpressionTermInfo()
            {
                public Method getReadMethod()
                {
                    return adapter.getReadMethod();
                }
                public Method getWriteMethod()
                {
                    return adapter.getWriteMethod();
                }
                public Class getType()
                {
                    return adapter.getType();
                }
                public boolean isCastRequired()
                {
                    return adapter.isCastRequired();
                }
                public String getDescription()
                {
                    return adapter.getName();
                }
                public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
                {
                    return adapter.getAnnotation(annotationClass);
                }
                public String getPropertyName()
                {
                    return adapter.getName();
                }
                public boolean isField()
                {
                    return adapter.isField();
                }
                public Field getField()
                {
                    return adapter.getField();
                }
            };
        }
        private ExpressionTermInfo infoForInvokeNode(Class activeTypeTree node)
        {
            String methodName = node.getChild(0).getText();
            int parameterCount = node.getChildCount() - 1;
            try
            {
                final Method method = findMethod(activeTypemethodNameparameterCount);
                if (method.getReturnType().equals(void.class))
                    throw new RuntimeException(String.format("Method %s.%s() returns void."activeType.getName(),
                            methodName));
                final Class genericType = GenericsUtils.extractGenericReturnType(activeTypemethod);
                return new ExpressionTermInfo()
                {
                    public Method getReadMethod()
                    {
                        return method;
                    }
                    public Method getWriteMethod()
                    {
                        return null;
                    }
                    public Class getType()
                    {
                        return genericType;
                    }
                    public boolean isCastRequired()
                    {
                        return genericType != method.getReturnType();
                    }
                    public String getDescription()
                    {
                        return new MethodSignature(method).getUniqueId();
                    }
                    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
                    {
                        return method.getAnnotation(annotationClass);
                    }
                    public String getPropertyName()
                    {
                        return null;
                    }
                    public boolean isField()
                    {
                        return false;
                    }
                    public Field getField()
                    {
                        return null;
                    }
                };
            }
          &