|
|
@@ -9,11 +9,13 @@ package net.ranides.assira.reflection;
|
|
|
|
|
|
import java.io.Serializable;
|
|
|
import java.util.Arrays;
|
|
|
+import java.util.Iterator;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.regex.Matcher;
|
|
|
import java.util.regex.Pattern;
|
|
|
import net.ranides.assira.collection.arrays.NativeArray;
|
|
|
+import net.ranides.assira.generic.SerializationUtils;
|
|
|
import net.ranides.assira.generic.Wrapper;
|
|
|
import net.ranides.assira.reflection.impl.RCompareUtils;
|
|
|
import net.ranides.assira.text.StringTraits;
|
|
|
@@ -26,14 +28,17 @@ import net.ranides.assira.text.StringUtils;
|
|
|
public class Resolver implements Serializable {
|
|
|
|
|
|
private static final long serialVersionUID = 1L;
|
|
|
-
|
|
|
+
|
|
|
private static final Pattern RE_INDEX = Pattern.compile("\\[([^\\]]+)\\]");
|
|
|
|
|
|
+ private final String expression;
|
|
|
+
|
|
|
private final String[] tokens;
|
|
|
|
|
|
private Resolver(String expression) {
|
|
|
assert expression != null;
|
|
|
String[] array = StringUtils.replace(expression, RE_INDEX, m -> "."+m.group(1)+".").split("\\.");
|
|
|
+ this.expression = expression;
|
|
|
this.tokens = Arrays.stream(array).filter(p->!p.isEmpty()).toArray(String[]::new);
|
|
|
}
|
|
|
|
|
|
@@ -83,78 +88,129 @@ public class Resolver implements Serializable {
|
|
|
return compile(expression).bind(that);
|
|
|
}
|
|
|
|
|
|
+ public String expression() {
|
|
|
+ return expression;
|
|
|
+ }
|
|
|
+
|
|
|
public Object get(Object that) {
|
|
|
- for(String token :tokens) {
|
|
|
- that = iget(that, token);
|
|
|
+ ErrorHandler eh = new ErrorHandler();
|
|
|
+ for(int i=0,n=tokens.length-1; i<n; i++) {
|
|
|
+ that = iget(eh, that, tokens[i]);
|
|
|
+ if(eh.isError()) {
|
|
|
+ return eh.handleNoValuePath();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ that = iget(eh, that, tokens[tokens.length-1]);
|
|
|
+ if(eh.isError()) {
|
|
|
+ eh.handleNoValue();
|
|
|
}
|
|
|
return that;
|
|
|
}
|
|
|
|
|
|
public void set(Object that, Object value) {
|
|
|
+ ErrorHandler eh = new ErrorHandler();
|
|
|
for(int i=0,n=tokens.length-1; i<n; i++) {
|
|
|
- that = iget(that, tokens[i]);
|
|
|
+ that = iget(eh, that, tokens[i]);
|
|
|
+ if(eh.isError()) {
|
|
|
+ eh.handleNoValuePath();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ iset(eh, that, tokens[tokens.length-1], value);
|
|
|
+ if(eh.isError()) {
|
|
|
+ eh.handleNoSet();
|
|
|
}
|
|
|
- iset(that, tokens[tokens.length-1], value);
|
|
|
}
|
|
|
|
|
|
public Object replace(Object that, Object value) {
|
|
|
+ ErrorHandler eh = new ErrorHandler();
|
|
|
for(int i=0,n=tokens.length-1; i<n; i++) {
|
|
|
- that = iget(that, tokens[i]);
|
|
|
+ that = iget(eh, that, tokens[i]);
|
|
|
+ if(eh.isError()) {
|
|
|
+ eh.handleNoValuePath();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Object out = ireplace(eh, that, tokens[tokens.length-1], value);
|
|
|
+ if(eh.isError()) {
|
|
|
+ return eh.handleNoReplace();
|
|
|
}
|
|
|
- return ireplace(that, tokens[tokens.length-1], value);
|
|
|
+ return out;
|
|
|
}
|
|
|
|
|
|
public IClass<?> type(Object that) {
|
|
|
+ ErrorHandler eh = new ErrorHandler();
|
|
|
IClass<?> type = IClass.typefor(that);
|
|
|
for(int i=0,n=tokens.length-1; i<n; i++) {
|
|
|
- type = itype(type, tokens[i]);
|
|
|
+ type = itype(eh, type, tokens[i]);
|
|
|
+ if(eh.isError()) {
|
|
|
+ return eh.handleNoTypePath();
|
|
|
+ }
|
|
|
}
|
|
|
- return itype(type, tokens[tokens.length-1]);
|
|
|
+ IClass<?> out = itype(eh, type, tokens[tokens.length-1]);
|
|
|
+ if(eh.isError()) {
|
|
|
+ return eh.handleNoType();
|
|
|
+ }
|
|
|
+ return out;
|
|
|
}
|
|
|
|
|
|
public Wrapper<Object> bind(Object that) {
|
|
|
return new RWrapper(that);
|
|
|
}
|
|
|
|
|
|
- private Object iget(Object that, String name) {
|
|
|
+ private Object iget(ErrorHandler handler, Object that, String name) {
|
|
|
for(Model m : MODELS) {
|
|
|
if(m.matches(that)) {
|
|
|
- return m.get(that, name);
|
|
|
+ return m.get(handler, that, name);
|
|
|
}
|
|
|
}
|
|
|
throw new IllegalArgumentException("Illegal value: " + that);
|
|
|
}
|
|
|
|
|
|
- private void iset(Object that, String name, Object value) {
|
|
|
+ private void iset(ErrorHandler handler, Object that, String name, Object value) {
|
|
|
for(Model m : MODELS) {
|
|
|
if(m.matches(that)) {
|
|
|
- m.set(that, name, value);
|
|
|
+ m.set(handler, that, name, value);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
throw new IllegalArgumentException("Illegal value: " + that);
|
|
|
}
|
|
|
|
|
|
- private Object ireplace(Object that, String name, Object value) {
|
|
|
+ private Object ireplace(ErrorHandler handler, Object that, String name, Object value) {
|
|
|
for(Model m : MODELS) {
|
|
|
if(m.matches(that)) {
|
|
|
- return m.replace(that, name, value);
|
|
|
+ return m.replace(handler, that, name, value);
|
|
|
}
|
|
|
}
|
|
|
throw new IllegalArgumentException("Illegal value: " + that);
|
|
|
}
|
|
|
|
|
|
- private IClass<?> itype(IClass<?> that, String name) {
|
|
|
+ private IClass<?> itype(ErrorHandler handler, IClass<?> that, String name) {
|
|
|
for(Model m : MODELS) {
|
|
|
if(m.matchesType(that)) {
|
|
|
- return m.type(that, name);
|
|
|
+ return m.type(handler, that, name);
|
|
|
}
|
|
|
}
|
|
|
throw new IllegalArgumentException("Illegal value: " + that);
|
|
|
}
|
|
|
|
|
|
+ private Object writeReplace() {
|
|
|
+ return SerializationUtils.proxy(this, expression);
|
|
|
+ }
|
|
|
+
|
|
|
private static final Model[] MODELS = Model.values();
|
|
|
|
|
|
+ public static class ResolveException extends IllegalArgumentException {
|
|
|
+
|
|
|
+ public ResolveException(String message) {
|
|
|
+ super(message);
|
|
|
+ }
|
|
|
+
|
|
|
+ public ResolveException(Throwable cause) {
|
|
|
+ super(cause);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
private enum Model {
|
|
|
ARRAY(){
|
|
|
@Override
|
|
|
@@ -166,19 +222,19 @@ public class Resolver implements Serializable {
|
|
|
return IAttribute.ARRAY.matches(that);
|
|
|
}
|
|
|
@Override
|
|
|
- public Object get(Object that, String name) {
|
|
|
+ public Object get(ErrorHandler _h, Object that, String name) {
|
|
|
return NativeArray.wrap(that).get(Integer.parseInt(name));
|
|
|
}
|
|
|
@Override
|
|
|
- public void set(Object that, String name, Object value) {
|
|
|
+ public void set(ErrorHandler _h, Object that, String name, Object value) {
|
|
|
NativeArray.wrap(that).set(Integer.parseInt(name), value);
|
|
|
}
|
|
|
@Override
|
|
|
- public Object replace(Object that, String name, Object value) {
|
|
|
+ public Object replace(ErrorHandler _h, Object that, String name, Object value) {
|
|
|
return NativeArray.wrap(that).replace(Integer.parseInt(name), value);
|
|
|
}
|
|
|
@Override
|
|
|
- public IClass<?> type(IClass<?> that, String name) {
|
|
|
+ public IClass<?> type(ErrorHandler _h, IClass<?> that, String name) {
|
|
|
return that.component();
|
|
|
}
|
|
|
},
|
|
|
@@ -192,17 +248,17 @@ public class Resolver implements Serializable {
|
|
|
return that!=IClass.NULL && RCompareUtils.isRawSuper(IClass.typeinfo(List.class), that);
|
|
|
}
|
|
|
@Override
|
|
|
- public Object get(Object that, String name) {
|
|
|
+ public Object get(ErrorHandler _h, Object that, String name) {
|
|
|
return ((List<?>)that).get(Integer.parseInt(name));
|
|
|
}
|
|
|
@Override
|
|
|
@SuppressWarnings("unchecked")
|
|
|
- public void set(Object that, String name, Object value) {
|
|
|
+ public void set(ErrorHandler _h, Object that, String name, Object value) {
|
|
|
((List<Object>)that).set(Integer.parseInt(name), value);
|
|
|
}
|
|
|
@Override
|
|
|
@SuppressWarnings("unchecked")
|
|
|
- public Object replace(Object that, String name, Object value) {
|
|
|
+ public Object replace(ErrorHandler _h, Object that, String name, Object value) {
|
|
|
List<Object> list = (List<Object>)that;
|
|
|
int index = Integer.parseInt(name);
|
|
|
Object prv = list.get(index);
|
|
|
@@ -210,7 +266,7 @@ public class Resolver implements Serializable {
|
|
|
return prv;
|
|
|
}
|
|
|
@Override
|
|
|
- public IClass<?> type(IClass<?> that, String name) {
|
|
|
+ public IClass<?> type(ErrorHandler _h, IClass<?> that, String name) {
|
|
|
return that.params().get(0);
|
|
|
}
|
|
|
},
|
|
|
@@ -224,21 +280,21 @@ public class Resolver implements Serializable {
|
|
|
return that!=IClass.NULL && RCompareUtils.isRawSuper(IClass.typeinfo(Map.class), that);
|
|
|
}
|
|
|
@Override
|
|
|
- public Object get(Object that, String name) {
|
|
|
+ public Object get(ErrorHandler _h, Object that, String name) {
|
|
|
return ((Map<?,?>)that).get(name);
|
|
|
}
|
|
|
@Override
|
|
|
@SuppressWarnings("unchecked")
|
|
|
- public void set(Object that, String name, Object value) {
|
|
|
+ public void set(ErrorHandler _h, Object that, String name, Object value) {
|
|
|
((Map<String,Object>)that).put(name, value);
|
|
|
}
|
|
|
@Override
|
|
|
@SuppressWarnings("unchecked")
|
|
|
- public Object replace(Object that, String name, Object value) {
|
|
|
+ public Object replace(ErrorHandler _h, Object that, String name, Object value) {
|
|
|
return ((Map<String,Object>)that).put(name, value);
|
|
|
}
|
|
|
@Override
|
|
|
- public IClass<?> type(IClass<?> that, String name) {
|
|
|
+ public IClass<?> type(ErrorHandler _h, IClass<?> that, String name) {
|
|
|
return that.params().get(1);
|
|
|
}
|
|
|
},
|
|
|
@@ -252,7 +308,7 @@ public class Resolver implements Serializable {
|
|
|
return that!=IClass.NULL && IClass.typeinfo(Matcher.class).isSuper(that);
|
|
|
}
|
|
|
@Override
|
|
|
- public Object get(Object that, String name) {
|
|
|
+ public Object get(ErrorHandler _h, Object that, String name) {
|
|
|
if(StringTraits.isNumber(name)) {
|
|
|
return ((Matcher)that).group(Integer.parseInt(name));
|
|
|
} else {
|
|
|
@@ -260,15 +316,15 @@ public class Resolver implements Serializable {
|
|
|
}
|
|
|
}
|
|
|
@Override
|
|
|
- public void set(Object that, String name, Object value) {
|
|
|
+ public void set(ErrorHandler _h, Object that, String name, Object value) {
|
|
|
throw new UnsupportedOperationException("Matcher is immutable.");
|
|
|
}
|
|
|
@Override
|
|
|
- public Object replace(Object that, String name, Object value) {
|
|
|
+ public Object replace(ErrorHandler _h, Object that, String name, Object value) {
|
|
|
throw new UnsupportedOperationException("Matcher is immutable.");
|
|
|
}
|
|
|
@Override
|
|
|
- public IClass<?> type(IClass<?> that, String name) {
|
|
|
+ public IClass<?> type(ErrorHandler _h, IClass<?> that, String name) {
|
|
|
return IClass.typeinfo(String.class);
|
|
|
}
|
|
|
},
|
|
|
@@ -282,19 +338,19 @@ public class Resolver implements Serializable {
|
|
|
return that!=IClass.NULL && IClass.typeinfo(CharSequence.class).isSuper(that);
|
|
|
}
|
|
|
@Override
|
|
|
- public Object get(Object that, String name) {
|
|
|
+ public Object get(ErrorHandler _h, Object that, String name) {
|
|
|
return ((CharSequence)that).charAt(Integer.parseInt(name));
|
|
|
}
|
|
|
@Override
|
|
|
- public void set(Object that, String name, Object value) {
|
|
|
+ public void set(ErrorHandler _h, Object that, String name, Object value) {
|
|
|
throw new UnsupportedOperationException("CharSequence is immutable.");
|
|
|
}
|
|
|
@Override
|
|
|
- public Object replace(Object that, String name, Object value) {
|
|
|
+ public Object replace(ErrorHandler _h, Object that, String name, Object value) {
|
|
|
throw new UnsupportedOperationException("CharSequence is immutable.");
|
|
|
}
|
|
|
@Override
|
|
|
- public IClass<?> type(IClass<?> that, String name) {
|
|
|
+ public IClass<?> type(ErrorHandler _h, IClass<?> that, String name) {
|
|
|
return IClass.typeinfo(char.class);
|
|
|
}
|
|
|
},
|
|
|
@@ -308,40 +364,62 @@ public class Resolver implements Serializable {
|
|
|
return that!=IClass.NULL;
|
|
|
}
|
|
|
@Override
|
|
|
- public Object get(Object that, String name) {
|
|
|
+ public Object get(ErrorHandler handler, Object that, String name) {
|
|
|
BeanModel model = BeanModel.typefor(that);
|
|
|
if(model.properties().containsKey(name)) {
|
|
|
return model.property(name).get(that);
|
|
|
- } else {
|
|
|
- return model.type().field(name).get(that);
|
|
|
+ }
|
|
|
+ Iterator<IField> f = field(model, name);
|
|
|
+ if(f.hasNext()) {
|
|
|
+ return f.next().get(that);
|
|
|
}
|
|
|
+ handler.failure();
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Iterator<IField> field(BeanModel model, String name) {
|
|
|
+ return model.type().fields().require(IAttribute.ANY).require(name).iterator();
|
|
|
}
|
|
|
+
|
|
|
@Override
|
|
|
- public void set(Object that, String name, Object value) {
|
|
|
+ public void set(ErrorHandler handler, Object that, String name, Object value) {
|
|
|
BeanModel model = BeanModel.typefor(that);
|
|
|
if(model.properties().containsKey(name)) {
|
|
|
model.property(name).set(that, value);
|
|
|
- } else {
|
|
|
- model.type().field(name).set(that, value);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Iterator<IField> f = field(model, name);
|
|
|
+ if(f.hasNext()) {
|
|
|
+ f.next().set(that, value);
|
|
|
+ return;
|
|
|
}
|
|
|
+ handler.failure();
|
|
|
}
|
|
|
@Override
|
|
|
- public Object replace(Object that, String name, Object value) {
|
|
|
+ public Object replace(ErrorHandler handler, Object that, String name, Object value) {
|
|
|
BeanModel model = BeanModel.typefor(that);
|
|
|
if(model.properties().containsKey(name)) {
|
|
|
return model.property(name).replace(that, value);
|
|
|
- } else {
|
|
|
- return model.type().field(name).replace(that, value);
|
|
|
}
|
|
|
+ Iterator<IField> f = field(model, name);
|
|
|
+ if(f.hasNext()) {
|
|
|
+ return f.next().replace(that, value);
|
|
|
+ }
|
|
|
+ handler.failure();
|
|
|
+ return null;
|
|
|
}
|
|
|
@Override
|
|
|
- public IClass<?> type(IClass<?> that, String name) {
|
|
|
+ public IClass<?> type(ErrorHandler handler, IClass<?> that, String name) {
|
|
|
BeanModel model = BeanModel.typeinfo(that);
|
|
|
if(model.properties().containsKey(name)) {
|
|
|
return model.property(name).type();
|
|
|
- } else {
|
|
|
- return model.type().field(name).type();
|
|
|
}
|
|
|
+ Iterator<IField> f = field(model, name);
|
|
|
+ if(f.hasNext()) {
|
|
|
+ return f.next().type();
|
|
|
+ }
|
|
|
+ handler.failure();
|
|
|
+ return null;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
@@ -349,13 +427,13 @@ public class Resolver implements Serializable {
|
|
|
|
|
|
public abstract boolean matches(Object that);
|
|
|
|
|
|
- public abstract Object get(Object that, String name);
|
|
|
+ public abstract Object get(ErrorHandler handler, Object that, String name);
|
|
|
|
|
|
- public abstract void set(Object that, String name, Object value);
|
|
|
+ public abstract void set(ErrorHandler handler, Object that, String name, Object value);
|
|
|
|
|
|
- public abstract Object replace(Object that, String name, Object value);
|
|
|
+ public abstract Object replace(ErrorHandler handler, Object that, String name, Object value);
|
|
|
|
|
|
- public abstract IClass<?> type(IClass<?> that, String name);
|
|
|
+ public abstract IClass<?> type(ErrorHandler handler, IClass<?> that, String name);
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -389,4 +467,43 @@ public class Resolver implements Serializable {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ private static class ErrorHandler {
|
|
|
+
|
|
|
+ // @todo (assira #1) Resolver.ErrorHandler
|
|
|
+
|
|
|
+ public boolean error = false;
|
|
|
+
|
|
|
+ public final void failure() {
|
|
|
+ error = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public final boolean isError() {
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Object handleNoValue() {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Object handleNoValuePath() {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public IClass<?> handleNoType() {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public IClass<?> handleNoTypePath() {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Object handleNoReplace() {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void handleNoSet() {
|
|
|
+ // do something
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
}
|