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

VotersWatch issueWatchersLinkCloneUpdate Comment AuthorReplace String in CommentUpdate Comment VisibilityDelete Comments
    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

          This comment will be Viewable by All Users Viewable by All Users
          Cancel

          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:

              Slack

                Issue deployment