use of beast.util.XMLParser.NameValuePair in project beast2 by CompEvol.
the class JSONParser method useAnnotatedConstructor.
@SuppressWarnings({ "rawtypes", "unchecked" })
private BEASTInterface useAnnotatedConstructor(JSONObject node, String _id, String clazzName, List<NameValuePair> inputInfo) throws JSONParserException {
Class<?> clazz = null;
try {
clazz = Class.forName(clazzName);
} catch (ClassNotFoundException e) {
// cannot get here, since we checked the class existed before
e.printStackTrace();
}
Constructor<?>[] allConstructors = clazz.getDeclaredConstructors();
for (Constructor<?> ctor : allConstructors) {
// collect Param annotations on constructor parameters
Annotation[][] annotations = ctor.getParameterAnnotations();
List<Param> paramAnnotations = new ArrayList<>();
for (Annotation[] a0 : annotations) {
for (Annotation a : a0) {
if (a instanceof Param) {
paramAnnotations.add((Param) a);
}
}
}
for (NameValuePair pair : inputInfo) {
pair.processed = false;
}
Class<?>[] types = ctor.getParameterTypes();
if (types.length > 0 && paramAnnotations.size() == types.length) {
try {
// if all constructor parameters have Param annotations, try to call constructor
// first, build up argument list, then create object
Object[] args = new Object[types.length];
for (int i = 0; i < types.length; i++) {
Param param = paramAnnotations.get(i);
Type type = types[i];
if (type.getTypeName().equals("java.util.List")) {
if (args[i] == null) {
// no need to parameterise list due to type erasure
args[i] = new ArrayList();
}
List<Object> values = XMLParser.getListOfValues(param, inputInfo);
((List<Object>) args[i]).addAll(values);
} else {
args[i] = getValue(param, (Class<?>) type, inputInfo);
}
}
// ensure all inputs are used
boolean allUsed = true;
for (NameValuePair pair : inputInfo) {
if (!pair.processed) {
allUsed = false;
}
}
// if all inputs are used, call the constructor, otherwise, look for another constructor
if (allUsed) {
try {
Object o = ctor.newInstance(args);
BEASTInterface beastObject = (BEASTInterface) o;
register(node, beastObject);
return beastObject;
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new JSONParserException(node, "Could not create object: " + e.getMessage(), 1012);
}
}
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// we get here when a param value cannot be constructed from a default value
// let's try the next constructor (if any)
}
}
}
return null;
}
use of beast.util.XMLParser.NameValuePair in project beast2 by CompEvol.
the class JSONParser method processInput.
// setInputs
private void processInput(String name, JSONObject node, List<NameValuePair> map, List<InputType> inputs) throws JSONParserException, JSONException {
if (node.has(name)) {
if (!(name.equals("id") || name.equals("idref") || name.equals("spec") || name.equals("name"))) {
Object o = node.get(name);
if (o instanceof String) {
String value = (String) o;
if (value.startsWith("@")) {
String IDRef = value.substring(1);
JSONObject element = new JSONObject();
element.put("idref", IDRef);
BEASTInterface beastObject = createObject(element, BEAST_OBJECT_CLASS);
map.add(new NameValuePair(name, beastObject));
// setInput(node, parent, name, beastObject);
} else {
map.add(new NameValuePair(name, value));
// setInput(node, parent, name, value);
}
} else if (o instanceof Number) {
map.add(new NameValuePair(name, o));
// parent.setInputValue(name, o);
} else if (o instanceof Boolean) {
map.add(new NameValuePair(name, o));
// parent.setInputValue(name, o);
} else if (o instanceof JSONObject) {
JSONObject child = (JSONObject) o;
String className = getClassName(child, name, inputs);
BEASTInterface childItem = createObject(child, className);
if (childItem != null) {
map.add(new NameValuePair(name, childItem));
// setInput(node, parent, name, childItem);
}
// childElements++;
} else if (o instanceof JSONArray) {
JSONArray list = (JSONArray) o;
for (int i = 0; i < list.length(); i++) {
Object o2 = list.get(i);
if (o2 instanceof JSONObject) {
JSONObject child = (JSONObject) o2;
String className = getClassName(child, name, inputs);
BEASTInterface childItem = createObject(child, className);
if (childItem != null) {
map.add(new NameValuePair(name, childItem));
// setInput(node, parent, name, childItem);
}
} else {
map.add(new NameValuePair(name, o2));
// parent.setInputValue(name, o2);
}
}
} else {
throw new RuntimeException("Developer error: Don't know how to handle this JSON construction");
}
}
}
}
use of beast.util.XMLParser.NameValuePair in project beast2 by CompEvol.
the class JSONParser method getValue.
/**
* get value from inputInfo, but use default if the Param name cannot be found in inputInfo
* RRB: would like to combine with XMLParser.getValue, but this may get ugly due to incompatible XML/JSON types
*/
private Object getValue(Param param, Class<?> clazz, List<NameValuePair> inputInfo) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
for (NameValuePair pair : inputInfo) {
if (pair.name.equals(param.name())) {
pair.processed = true;
return pair.value;
}
}
// check if this parameter is required or optional
if (!param.optional()) {
throw new IllegalArgumentException();
}
// try using a String constructor of the default value
Constructor<?> ctor;
String value = param.defaultValue();
Object v = value;
try {
ctor = clazz.getDeclaredConstructor(String.class);
} catch (NoSuchMethodException e) {
// try integer constructor instead
try {
if (value.startsWith("0x")) {
v = Integer.parseInt(value.substring(2), 16);
} else {
v = Integer.parseInt(value);
}
ctor = clazz.getDeclaredConstructor(int.class);
} catch (NumberFormatException e2) {
// could not parse as integer, try double instead
v = Double.parseDouble(value);
ctor = clazz.getDeclaredConstructor(double.class);
}
}
ctor.setAccessible(true);
final Object o = ctor.newInstance(v);
return o;
}
use of beast.util.XMLParser.NameValuePair in project beast2 by CompEvol.
the class JSONParser method createObject.
// checkType
/**
* create a BEAST object based on the info in the node.
* @param node
* @param className default class name -- this means a spec attribute does not need to be
* specified if all outputs of this BEAST object have as Input type the class of this object.
* @return
* @throws JSONParserException
*/
BEASTInterface createObject(JSONObject node, String className) throws JSONParserException {
// try the IDMap first
String ID = getID(node);
if (ID != null) {
if (IDMap.containsKey(ID)) {
BEASTInterface beastObject = IDMap.get(ID);
if (checkType(className, beastObject)) {
return beastObject;
}
throw new JSONParserException(node, "id=" + ID + ". Expected object of type " + className + " instead of " + beastObject.getClass().getName(), 105);
}
}
String IDRef = getIDRef(node);
if (IDRef != null) {
// produce warning if there are other attributes than idref
if (node.keySet().size() > 1) {
// check if there is just 1 attribute
Log.warning.println("Element " + getAttribute((JSONObject) node.getParent(), "name") + " found with idref='" + IDRef + "'. All other attributes are ignored.\n");
}
if (IDMap.containsKey(IDRef)) {
BEASTInterface beastObject = IDMap.get(IDRef);
if (checkType(className, beastObject)) {
return beastObject;
}
throw new JSONParserException(node, "id=" + IDRef + ". Expected object of type " + className + " instead of " + beastObject.getClass().getName(), 106);
} else if (IDNodeMap.containsKey(IDRef)) {
BEASTInterface beastObject = createObject(IDNodeMap.get(IDRef), className);
if (checkType(className, beastObject)) {
return beastObject;
}
throw new JSONParserException(node, "id=" + IDRef + ". Expected object of type " + className + " instead of " + beastObject.getClass().getName(), 107);
}
throw new JSONParserException(node, "Could not find object associated with idref " + IDRef, 170);
}
// it's not in the ID map yet, so we have to create a new object
String specClass = className;
String elementName = getElementName(node);
if (element2ClassMap.containsKey(elementName)) {
specClass = element2ClassMap.get(elementName);
}
String spec = getAttribute(node, "spec");
if (spec != null) {
specClass = spec;
}
String clazzName = null;
// determine clazzName from specName, taking name spaces in account
for (String nameSpace : nameSpaces) {
if (clazzName == null) {
if (XMLParserUtils.beastObjectNames.contains(nameSpace + specClass)) {
clazzName = nameSpace + specClass;
break;
}
}
}
if (clazzName == null) {
// try to create the old-fashioned way by creating the class
boolean isDone = false;
for (final String nameSpace : nameSpaces) {
try {
if (!isDone) {
Class.forName(nameSpace + specClass);
clazzName = nameSpace + specClass;
isDone = true;
}
} catch (ClassNotFoundException e) {
// class does not exist -- try another namespace
}
}
}
if (clazzName == null) {
throw new JSONParserException(node, "Class could not be found. Did you mean " + XMLParserUtils.guessClass(specClass) + "?", 1017);
// throw new ClassNotFoundException(specClass);
}
// sanity check
try {
Class<?> clazz = Class.forName(clazzName);
if (!BEASTInterface.class.isAssignableFrom(clazz)) {
// } else {
throw new JSONParserException(node, "Expected object to be instance of BEASTObject", 108);
// }
}
} catch (ClassNotFoundException e1) {
// should never happen since clazzName is in the list of classes collected by the PackageManager
e1.printStackTrace();
throw new RuntimeException(e1);
}
// process inputs
List<NameValuePair> inputInfo = parseInputs(node, clazzName);
BEASTInterface beastObject = createBeastObject(node, ID, clazzName, inputInfo);
// initialise
if (initialise) {
try {
beastObject.determindClassOfInputs();
beastObject.validateInputs();
objectsWaitingToInit.add(new BEASTObjectWrapper(beastObject, node));
// beastObject.initAndValidate();
} catch (IllegalArgumentException e) {
// next lines for debugging only
// beastObject.validateInputs();
// beastObject.initAndValidate();
e.printStackTrace();
throw new JSONParserException(node, "validate and intialize error: " + e.getMessage(), 110);
}
}
return beastObject;
}
use of beast.util.XMLParser.NameValuePair in project beast2 by CompEvol.
the class JSONParser method createBeastObject.
/**
* create BEASTInterface either using Inputs, or using annotated constructor *
*/
private BEASTInterface createBeastObject(JSONObject node, String ID, String clazzName, List<NameValuePair> inputInfo) throws JSONParserException {
BEASTInterface beastObject = useAnnotatedConstructor(node, ID, clazzName, inputInfo);
if (beastObject != null) {
return beastObject;
}
// create new instance using class name
Object o = null;
try {
Class<?> c = Class.forName(clazzName);
o = c.newInstance();
} catch (InstantiationException e) {
// created for instance because it is abstract
throw new JSONParserException(node, "Cannot instantiate class. Please check the spec attribute.", 1006);
} catch (ClassNotFoundException e) {
// ignore -- class was found in beastObjectNames before
} catch (IllegalAccessException e) {
// T O D O Auto-generated catch block
e.printStackTrace();
throw new JSONParserException(node, "Cannot access class. Please check the spec attribute.", 1011);
}
// set id
beastObject = (BEASTInterface) o;
beastObject.setID(ID);
// hack required to make log-parsing easier
if (o instanceof State) {
state = (State) o;
}
// process inputs for annotated constructors
for (NameValuePair pair : inputInfo) {
setInput(node, beastObject, pair.name, pair.value);
}
// fill in missing inputs, if an input provider is available
try {
if (requiredInputProvider != null) {
for (Input<?> input : beastObject.listInputs()) {
if (input.get() == null && input.getRule() == Validate.REQUIRED) {
Object o2 = requiredInputProvider.createInput(beastObject, input, partitionContext);
if (o2 != null) {
input.setValue(o2, beastObject);
}
}
}
}
} catch (Exception e) {
throw new JSONParserException(node, e.getMessage(), 1008);
}
// sanity check: all attributes should be valid input names
if (!(beastObject instanceof Map)) {
for (String name : node.keySet()) {
if (!(name.equals("id") || name.equals("idref") || name.equals("spec") || name.equals("name"))) {
try {
beastObject.getInput(name);
} catch (Exception e) {
throw new JSONParserException(node, e.getMessage(), 1009);
}
}
}
}
// make sure object o is in outputs of inputs
for (NameValuePair pair : inputInfo) {
if (pair.value instanceof BEASTInterface) {
((BEASTInterface) pair.value).getOutputs().add((BEASTInterface) o);
}
}
register(node, beastObject);
return beastObject;
}
Aggregations