Announcement Announcement Module
Collapse
No announcement yet.
Autogrow collections on Javassist proxy failing Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Autogrow collections on Javassist proxy failing

    Hi,

    Here's the problem. I have an JPA-2 entity that I use as a backing model for a controller. Here's what it looks like (pseudo-code):

    Code:
    @Entity
    class Order {
      
       @OneToMany
        List<Item> items;
    
    }
    
    @Entity
    class Item {
        
        @OneToMany
        List<Attribute> attributes;     
    
    }
    
    @Entity
    class Attribute {
        
        String someProperty;
    
    }
    I'm trying to bind form fields to the deepest level in that entity hierarchy like so:

    Code:
    <form:form modelAttribute="order">
        <form:input path="items[0].attributes[4].someProperty" />
    </form:form>
    The problem is that the "order" is a persistent entity loaded by Hibernate in a controller method annotated with @ModelAttribute. During the loading process, Hibernate turns all my items into Javassist proxies (to handle all the lazy-loading stuff of its relationships). Then, when the BreanWrapperImpl class tries to autogrow the "attributes" collection inside a given instance of Item, it fails to identify the generic type of the "attributes" collection (even if it's properly defined using a java.util.List<Attribute>). The Javassist proxies seem to screw up the reflection logic that the BeanWrapperImpl class uses to analyze the read method signature to figure out what class to instantiate to autogrow the collection; the org.springframework.core.GenericCollectionTypeReso lver.getCollectionReturnType(Method, int) method returns null for that property (i.e. the "attributes" property of the Item class). In such cases, the BeanWrapperImpl simply does not autogrow the collection. Obviously this causes IndexOutOfBoundsException during the binding process.

    Did anyone ever run into that particular problem? Do you have any idea how to fix/address it? I could find a way to go back behind Hibernate and manually unproxy all the classes that I know I will have data to bind on, but I was looking for a better way. Plus, doing so would prevent further lazy-loading of attributes since the entities won't be proxies anymore. I would consider that a bug that Spring does not handle Javassist proxies properly in that case, but I wanted to check here first before filing a bug in JIRA.

    Thank you for your help.

  • #2
    I found a workaround for now. In the method @ModelAttribute annotated controller method, after I load the root entity from the database, I navigate through the entity graph and replace every List instance with Spring's AutoPopulatingList. After that, when the BeanWrapperImpl binds the data, the AutoPopulatingList autogrow themselves as opposed to the BeanWrapperImpl doing the job himself.

    Code:
    @ModelAttribute
    public Order loadOrder(@PathVariable("id") Long id) {
        Order order = loadFromDatabase(id);
        order.setItems(new AutoPopulatingList(order.getItems(), Item.class));
        for (Item item : order.getItems()) {
            item.setAttributes(new AutoPopulatingList(item.getAttributes(), Attribute.class));
        }
        return order;
    }
    Works for now, but can be quite cumbersome if you have a complicated graph model. I'd still be curious to find a more elegant solution.

    Comment

    Working...
    X