Menu

#10 java.lang.StackOverflowError for recursive data objects

open
nobody
None
5
2008-07-03
2008-07-03
No

When class has member of its own type (e.g. child-parent) structures method processAccessTypeProperty (AbstractPersisistentClassIntrospector) is called recursively until stackOverflow error.

M

Discussion

  • Nobody/Anonymous

    Is anyone working this or have a solution?

     
  • kenundrum

    kenundrum - 2009-06-23

    Has there been any advancement from anybody on this issue?

     
  • Sergey Sedov

    Sergey Sedov - 2009-09-26

    In com.bm.introspectors.AbstractPersistentClassIntrospector in methods processAccessTypeField and processAccessTypeProperty separated processing of OneToMany and ManyToOne annotations.

    Works fine.

    protected void processAccessTypeField(Class<T> toInspect) {
    this.representingClass = toInspect;
    // extract meta information
    Class<? super T> clazz = toInspect;
    do {
    Field[] fields = clazz.getDeclaredFields();
    for (Field aktField : fields) {
    // dontіs introspect fields generated by hibernate
    if (!this.isStatic(aktField) && !aktField.getName().startsWith("$")) {
    Annotation[] fieldAnnotations = aktField.getAnnotations();
    if (aktField.getAnnotation(OneToMany.class) == null) {
    this.processAnnotations(toInspect, new Property(aktField), fieldAnnotations);
    }
    }
    }
    for (Field aktField : fields) {
    // dontіs introspect fields generated by hibernate
    if (!this.isStatic(aktField) && !aktField.getName().startsWith("$")) {
    Annotation[] fieldAnnotations = aktField.getAnnotations();
    if (aktField.getAnnotation(OneToMany.class) != null) {
    this.processAnnotations(toInspect, new Property(aktField), fieldAnnotations);
    }
    }
    }
    clazz = clazz.getSuperclass();
    }
    while (clazz != null && (clazz.getAnnotation(Entity.class) != null
    || clazz.getAnnotation(MappedSuperclass.class) != null));
    }

    protected void processAccessTypeProperty(Class<T> toInspect) {
    this.representingClass = toInspect;
    // extract meta information
    PropertyDescriptor[] properties = this.propUtils.getPropertyDescriptors(toInspect);

    for (PropertyDescriptor aktProperty : properties) {
    // dontіs introspect fields generated by hibernate
    if (!aktProperty.getReadMethod().getName().equals("getClass")) {
    Annotation[] methodAnnotations = aktProperty.getReadMethod().getAnnotations();

    if (aktProperty.getReadMethod().getAnnotation(OneToMany.class) == null) {
    this.processAnnotations(toInspect, new Property(toInspect, aktProperty), methodAnnotations);
    }

    }
    }
    for (PropertyDescriptor aktProperty : properties) {
    // dontіs introspect fields generated by hibernate
    if (!aktProperty.getReadMethod().getName().equals("getClass")) {
    Annotation[] methodAnnotations = aktProperty.getReadMethod().getAnnotations();

    if (aktProperty.getReadMethod().getAnnotation(OneToMany.class) != null) {
    this.processAnnotations(toInspect, new Property(toInspect, aktProperty), methodAnnotations);
    }

    }
    }
    }

     
  • Coder

    Coder - 2010-06-15

    Hi,

    I have a patch against 2.0.0.RC1 that fixes this issue. Please apply it to mainstream. Patch here:

    Index: main/java/com/bm/introspectors/relations/RelationPropertyResolver.java

    --- main/java/com/bm/introspectors/relations/RelationPropertyResolver.java (revision 308)
    +++ main/java/com/bm/introspectors/relations/RelationPropertyResolver.java (working copy)
    @@ -34,13 +34,15 @@
    if (relProp == null) {
    // use a new instrospector to put the relation to the global
    // store
    - final EntityBeanIntrospector<Object> tmpIn = new EntityBeanIntrospector<Object>(declaredInClass);
    + // Introspect just the required property, not all properties on target class
    + // to avoid infinite recursion in case a class references itself (parent-child)
    + final EntityBeanIntrospector<Object> tmpIn = new EntityBeanIntrospector<Object>(declaredInClass, mappedBy);
    log.debug("Dependend class: " + tmpIn.getTableName());
    // now it should be in theglobal store

    relProp = GlobalRelationStore.getStore().getProperty(declaredInClass, mappedBy);
    if (relProp == null) {
    - log.debug("The relation is unidirectional. Cant´t resolve releations for property (" + mappedBy
    + log.debug("The relation is unidirectional. Cant�t resolve releations for property (" + mappedBy
    + ") decared in class (" + declaredInClass.getName() + ")");
    }
    }
    @@ -57,8 +59,8 @@
    @SuppressWarnings("unchecked")
    public static Property findAttributeForRelationAtOtherSide(Property aktProperty) {
    // now look for the other if exist at the global store
    - // WIR MÜSSEN DIE N SEITE FINDEN: die als target uns hat (aktProperty)
    - // TODO WIR MÜSSEN DIE N SEITE FINDEN:
    + // WIR M�SSEN DIE N SEITE FINDEN: die als target uns hat (aktProperty)
    + // TODO WIR M�SSEN DIE N SEITE FINDEN:
    Property relProp = GlobalRelationStore.getStore().getProperty(aktProperty.getType(),
    aktProperty.getDeclaringClass());
    if (relProp == null) {
    Index: main/java/com/bm/introspectors/AbstractPersistentClassIntrospector.java
    ===================================================================
    --- main/java/com/bm/introspectors/AbstractPersistentClassIntrospector.java (revision 308)
    +++ main/java/com/bm/introspectors/AbstractPersistentClassIntrospector.java (working copy)
    @@ -73,18 +73,21 @@
    * @param toInspect -
    * the class to inspect
    */
    - protected void processAccessTypeField(Class<T> toInspect) {
    + protected void processAccessTypeField(Class<T> toInspect, String propertyName) {
    this.representingClass = toInspect;
    // extract meta information
    Class<? super T> clazz = toInspect;
    do {
    Field[] fields = clazz.getDeclaredFields();
    for (Field aktField : fields) {
    - // dont´s introspect fields generated by hibernate
    - if (!this.isStatic(aktField) && !aktField.getName().startsWith("$")) {
    - Annotation[] fieldAnnotations = aktField.getAnnotations();
    - this.processAnnotations(toInspect, new Property(aktField), fieldAnnotations);
    - }
    + // if we need to inspect just one property, inspect just one property
    + if (propertyName == null || propertyName.equals(aktField.getName())) {
    + // don't introspect fields generated by hibernate
    + if (!this.isStatic(aktField) && !aktField.getName().startsWith("$")) {
    + Annotation[] fieldAnnotations = aktField.getAnnotations();
    + this.processAnnotations(toInspect, new Property(aktField), fieldAnnotations);
    + }
    + }
    }
    clazz = clazz.getSuperclass();
    }
    @@ -99,18 +102,21 @@
    * @param toInspect -
    * the class to inspect
    */
    - protected void processAccessTypeProperty(Class<T> toInspect) {
    + protected void processAccessTypeProperty(Class<T> toInspect, String propertyName) {
    this.representingClass = toInspect;
    // extract meta information
    PropertyDescriptor[] properties = this.propUtils.getPropertyDescriptors(toInspect);

    for (PropertyDescriptor aktProperty : properties) {
    - // dont´s introspect fields generated by hibernate
    + // if we need to inspect just one property, inspect just one property
    + if (propertyName == null || propertyName.equals(aktProperty.getName())) {
    + // dont�s introspect fields generated by hibernate
    if (!aktProperty.getReadMethod().getName().equals("getClass")) {
    Annotation[] methodAnnotations = aktProperty.getReadMethod().getAnnotations();
    this.processAnnotations(toInspect, new Property(toInspect, aktProperty), methodAnnotations);

    }
    + }
    }
    }

    Index: main/java/com/bm/introspectors/EmbeddedClassIntrospector.java

    --- main/java/com/bm/introspectors/EmbeddedClassIntrospector.java (revision 308)
    +++ main/java/com/bm/introspectors/EmbeddedClassIntrospector.java (working copy)
    @@ -59,7 +59,7 @@
    }

    // TODO currently abbeded classses have always field access
    - this.processAccessTypeField(this.embeddedClassName);
    + this.processAccessTypeField(this.embeddedClassName, null);
    }

    /**
    Index: main/java/com/bm/introspectors/EntityBeanIntrospector.java
    ===================================================================
    --- main/java/com/bm/introspectors/EntityBeanIntrospector.java (revision 308)
    +++ main/java/com/bm/introspectors/EntityBeanIntrospector.java (working copy)
    @@ -68,13 +68,23 @@
    /** the type of the discriminator (if a single-table inheritance strategy is used) */
    private Class<?> discriminatorType;

    - /**
    - * Constructor with the class to inspect.
    - *
    - * @param toInspect -
    - * the class to inspect
    - */
    - public EntityBeanIntrospector(Class<T> toInspect) {
    + /**
    + * Constructor with the class to inspect.
    + *
    + * @param toInspect -
    + * the class to inspect
    + */
    + public EntityBeanIntrospector(Class<T> toInspect) {
    + this(toInspect, null);
    + }
    + /**
    + * Constructor with class to inspect. If given a property, inspects only that property,
    + * ignores all others. This is needed to allow inspection of classes that reference
    + * themselves.
    + *
    + * @param toInspect
    + */
    + public EntityBeanIntrospector(Class<T> toInspect, String propertyName) {

    this.toInspect = toInspect;
    Annotation[] classAnnotations = toInspect.getAnnotations();
    @@ -121,9 +131,9 @@
    }

    if (isAccessTypeField) {
    - this.processAccessTypeField(toInspect);
    + this.processAccessTypeField(toInspect, propertyName);
    } else {
    - this.processAccessTypeProperty(toInspect);
    + this.processAccessTypeProperty(toInspect, propertyName);
    }

    // Process Entity inheritance annotations (if any)
    @@ -141,12 +151,15 @@
    * @see com.bm.introspectors.AbstractPersistentClassIntrospector#processAccessTypeField(java.lang.Class)
    */
    @Override
    - protected void processAccessTypeField(Class<T> toInspect) {
    + protected void processAccessTypeField(Class<T> toInspect, String propertyName) {
    // class the super method
    - super.processAccessTypeField(toInspect);
    + super.processAccessTypeField(toInspect, propertyName);
    // extract meta information
    Field[] fields = toInspect.getDeclaredFields();
    for (Field aktField : fields) {
    + if (propertyName != null && !propertyName.equals(aktField.getName())) {
    + continue;
    + }
    // don't introspect fields generated by Hibernate
    Annotation[] fieldAnnotations = aktField.getAnnotations();

     

Log in to post a comment.