|
|
@@ -8,9 +8,7 @@
|
|
|
package net.ranides.assira.reflection.impl.bean;
|
|
|
|
|
|
import java.util.*;
|
|
|
-import java.util.stream.Collectors;
|
|
|
|
|
|
-import net.ranides.assira.collection.query.CQuery;
|
|
|
import net.ranides.assira.generic.CompareUtils;
|
|
|
import net.ranides.assira.reflection.*;
|
|
|
import net.ranides.assira.reflection.util.ClassUtils;
|
|
|
@@ -21,12 +19,21 @@ import net.ranides.assira.reflection.util.ClassUtils;
|
|
|
*
|
|
|
* It is created by RBeanModel and used by FBeanModel to create instance of specific BeanProperty implementation.
|
|
|
*
|
|
|
+ * Please note:
|
|
|
+ * We try to not throw exception on unexpected ill-formed methods which look like accessor, but they aren't.
|
|
|
+ * We simply ignore such methods. If you want to understand why some property is invisible in BeamModel, you should use
|
|
|
+ * #verify method.
|
|
|
+ *
|
|
|
+ * It is obvious and reasonable: we shouldn't throw errors for proper classes over which we do not have control just
|
|
|
+ * because they do not match some conventions (especially because some of them have really awkward edge cases)
|
|
|
+ *
|
|
|
* @author Ranides Atterwim {@literal <ranides@gmail.com>}
|
|
|
*/
|
|
|
public class RBeanPropertyBuilder {
|
|
|
|
|
|
+ private final IClass<?> parent;
|
|
|
private final String name;
|
|
|
-
|
|
|
+
|
|
|
private final List<IMethod> vsetters = new ArrayList<>(2);
|
|
|
private final List<IMethod> isetters = new ArrayList<>(2);
|
|
|
|
|
|
@@ -39,7 +46,8 @@ public class RBeanPropertyBuilder {
|
|
|
private IClass<?> type;
|
|
|
private IClass<?> item;
|
|
|
|
|
|
- RBeanPropertyBuilder(String name) {
|
|
|
+ RBeanPropertyBuilder(IClass<?> parent, String name) {
|
|
|
+ this.parent = parent;
|
|
|
this.name = name;
|
|
|
}
|
|
|
|
|
|
@@ -122,14 +130,15 @@ public class RBeanPropertyBuilder {
|
|
|
isetters.add(m);
|
|
|
}
|
|
|
|
|
|
- void validate() {
|
|
|
- initVSetter();
|
|
|
- initItem();
|
|
|
- initISetter();
|
|
|
- initType();
|
|
|
+ boolean validate(Collection<BeanException> errors) {
|
|
|
+ initVSetter(errors);
|
|
|
+ initItem(errors);
|
|
|
+ initISetter(errors);
|
|
|
+ initType(errors);
|
|
|
+ return type != null;
|
|
|
}
|
|
|
|
|
|
- private void initVSetter() throws IllegalArgumentException {
|
|
|
+ private void initVSetter(Collection<BeanException> errors) throws IllegalArgumentException {
|
|
|
if(vgetter != null) {
|
|
|
type = vgetter.returns();
|
|
|
vsetter = vsetters.stream().filter(m -> m.matches(type)).findFirst().orElse(null);
|
|
|
@@ -143,9 +152,11 @@ public class RBeanPropertyBuilder {
|
|
|
if(type != null) {
|
|
|
vsetter = vsetters.stream().filter(m -> m.matches(type)).findFirst().orElse(null);
|
|
|
}
|
|
|
- // just ignore ambiguous setters
|
|
|
+ if(errors != null) {
|
|
|
+ errors.add(new BeanException(parent, "WARN: Ambiguous setter: " + name));
|
|
|
+ }
|
|
|
}
|
|
|
- if( vsetters.size() == 1) {
|
|
|
+ else if( vsetters.size() == 1) {
|
|
|
vsetter = vsetters.get(0);
|
|
|
type = vsetter.arguments().types().first().get();
|
|
|
}
|
|
|
@@ -157,25 +168,33 @@ public class RBeanPropertyBuilder {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void initItem() throws IllegalArgumentException {
|
|
|
+ private void initItem(Collection<BeanException> errors) throws IllegalArgumentException {
|
|
|
if(type !=null && type.attributes().has(IAttribute.ARRAY)) {
|
|
|
item = type.component();
|
|
|
}
|
|
|
if(igetter != null) {
|
|
|
IClass<?> iitem = igetter.returns();
|
|
|
if( item!=null && !iitem.equals(item) ) {
|
|
|
- throw new IReflectiveException("Invalid array getter for: " + name);
|
|
|
+ if(errors != null) {
|
|
|
+ errors.add(new BeanException(parent, "WARN: Invalid array getter for: " + name));
|
|
|
+ }
|
|
|
+ item = null;
|
|
|
+ } else {
|
|
|
+ item = iitem;
|
|
|
}
|
|
|
- item = iitem;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void initISetter() throws IllegalArgumentException {
|
|
|
+ private void initISetter(Collection<BeanException> errors) throws IllegalArgumentException {
|
|
|
if(item != null) {
|
|
|
isetter = isetters.stream().filter(m -> m.matches(IClass.INT, item)).findFirst().orElse(null);
|
|
|
} else {
|
|
|
if( isetters.size() > 1) {
|
|
|
- throw new IReflectiveException("Ambiguous property setters for: " + name);
|
|
|
+ if(errors != null) {
|
|
|
+ errors.add(new BeanException(parent, "WARN: Ambiguous property indexed setters for: " + name));
|
|
|
+ }
|
|
|
+ isetter = null;
|
|
|
+ item = null;
|
|
|
}
|
|
|
if( isetters.size() == 1) {
|
|
|
isetter = isetters.get(0);
|
|
|
@@ -184,7 +203,7 @@ public class RBeanPropertyBuilder {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void initType() throws IllegalArgumentException {
|
|
|
+ private void initType(Collection<BeanException> errors) throws IllegalArgumentException {
|
|
|
if( null != item && null!=type) {
|
|
|
IClass<?> ctype = null;
|
|
|
if(type.attributes().has(IAttribute.ARRAY)) {
|
|
|
@@ -197,15 +216,22 @@ public class RBeanPropertyBuilder {
|
|
|
// if ctype is not array or collection, then it is false positive:
|
|
|
// property is not indexed at all and we ignore it safely
|
|
|
item = null;
|
|
|
+ if(errors != null) {
|
|
|
+ errors.add(new BeanException(parent, "HINT: False indexed property: " + name));
|
|
|
+ }
|
|
|
}
|
|
|
if (!CompareUtils.equals(item, ctype)) {
|
|
|
item = null;
|
|
|
- throw new IReflectiveException("Invalid type of indexed property: " + name);
|
|
|
+ if(errors != null) {
|
|
|
+ errors.add(new BeanException(parent, "WARN: Invalid type of indexed property: " + name));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(null == type && null==item) {
|
|
|
+ if(errors != null) {
|
|
|
+ errors.add(new BeanException(parent, "WARN: Unknown type of indexed property: " + name));
|
|
|
}
|
|
|
}
|
|
|
-// if(null == type && null==item) {
|
|
|
-// throw new IReflectiveException("Unknown type of indexed property: " + name);
|
|
|
-// }
|
|
|
if(type == null && item != null) {
|
|
|
type = IClass.generic(List.class, ClassUtils.box(item));
|
|
|
}
|