Uploaded image for project: 'Tapestry 5'
  1. Tapestry 5
  2. TAP5-1222

Accessing a public field of a non-component object inside component code can result in a TransfomationException if the accessed field name matches the name of a component field

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 5.2.0
    • 5.2.1
    • tapestry-core
    • None

    Description

      java.lang.ClassNotFoundException
      caught an exception while obtaining a class file for com.example.pages.category.CategoryIndex
      exception
      org.apache.tapestry5.ioc.internal.OperationException: javassist.CannotCompileException: [source error] _$get_category() not found in com.example.data.CategoryTreeNode
      org.apache.tapestry5.ioc.internal.OperationException
      javassist.CannotCompileException: [source error] _$get_category() not found in com.example.data.CategoryTreeNode
      trace
      Constructing instance of page class com.example.pages.category.CategoryIndex
      Creating ComponentAssembler for com.example.pages.category.CategoryIndex
      Transforming component class com.example.pages.category.CategoryIndex
      org.apache.tapestry5.internal.services.TransformationException
      javassist.CannotCompileException: [source error] _$get_category() not found in com.example.data.CategoryTreeNode

      Checking field read category in method $advised$getSubNodesForCurrentNode(): replacing with $ = $0._$get_category();

      @Cached(watch = "currentNode")
      public List<CategoryTreeNode> getSubNodesForCurrentNode()

      { if (currentNode.category == null) return Collections.emptyList(); return buildNodesForCategory(currentNode.category); }

      Because the CategoryIndex page has a field named "category", the transformation attempted to find it's replaced read access method, _$get_category(), in the non-component class (CategoryTreeNode).

      The fault is in here:

      ExprEditor editor = new ExprEditor()
      {
      private final Set<CtBehavior> addedMethods = CollectionFactory.newSet();

      {
      for (TransformMethodImpl tmi : methods.values())

      { if (tmi.added) addedMethods.add(tmi.method); }

      }

      public void edit(FieldAccess access) throws CannotCompileException
      {
      CtBehavior where = access.where();

      if (where instanceof CtConstructor)
      return;

      boolean isRead = access.isReader();
      String fieldName = access.getFieldName();
      CtMethod method = (CtMethod) where;

      formatter.format("Checking field %s %s in method %s(): ", isRead ? "read" : "write", fieldName,
      method.getName());

      // Ignore any methods to were added as part of the transformation.
      // If we reference the field there, we really mean the field.

      if (addedMethods.contains(where))

      { formatter.format("added method\n"); return; }

      Map<String, String> transformMap = isRead ? fieldReadTransforms : fieldWriteTransforms;

      String body = transformMap.get(fieldName);
      if (body == null)

      { formatter.format("field not transformed\n"); return; }

      formatter.format("replacing with %s\n", body);

      access.replace(body);
      }
      };

      Have to ensure that the field access is for a field of the component itself.

      Attachments

        Issue Links

          Activity

            People

              hlship Howard Lewis Ship
              hlship Howard Lewis Ship
              Votes:
              1 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: