When class has member of its own type (e.g. child-parent) structures method processAccessTypeProperty (AbstractPersisistentClassIntrospector) is called recursively until stackOverflow error.
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);
}
}
}
}
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
--- 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);
// 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) {
Is anyone working this or have a solution?
Has there been any advancement from anybody on this issue?
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);
}
}
}
}
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();