Search in sources :

Example 1 with NameValuePair

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;
}
Also used : ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) NameValuePair(beast.util.XMLParser.NameValuePair) Constructor(java.lang.reflect.Constructor) Annotation(java.lang.annotation.Annotation) InvocationTargetException(java.lang.reflect.InvocationTargetException) Type(java.lang.reflect.Type) Param(beast.core.Param) JSONObject(org.json.JSONObject) BEASTInterface(beast.core.BEASTInterface)

Example 2 with NameValuePair

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");
            }
        }
    }
}
Also used : NameValuePair(beast.util.XMLParser.NameValuePair) JSONObject(org.json.JSONObject) JSONArray(org.json.JSONArray) JSONObject(org.json.JSONObject) BEASTInterface(beast.core.BEASTInterface)

Example 3 with NameValuePair

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;
}
Also used : NameValuePair(beast.util.XMLParser.NameValuePair) JSONObject(org.json.JSONObject)

Example 4 with NameValuePair

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;
}
Also used : NameValuePair(beast.util.XMLParser.NameValuePair) JSONObject(org.json.JSONObject) BEASTInterface(beast.core.BEASTInterface)

Example 5 with NameValuePair

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;
}
Also used : NameValuePair(beast.util.XMLParser.NameValuePair) JSONException(org.json.JSONException) IOException(java.io.IOException) InvocationTargetException(java.lang.reflect.InvocationTargetException) State(beast.core.State) BEASTInterface(beast.core.BEASTInterface) JSONObject(org.json.JSONObject) HashMap(java.util.HashMap) Map(beast.core.parameter.Map)

Aggregations

NameValuePair (beast.util.XMLParser.NameValuePair)5 JSONObject (org.json.JSONObject)5 BEASTInterface (beast.core.BEASTInterface)4 InvocationTargetException (java.lang.reflect.InvocationTargetException)2 Param (beast.core.Param)1 State (beast.core.State)1 Map (beast.core.parameter.Map)1 IOException (java.io.IOException)1 Annotation (java.lang.annotation.Annotation)1 Constructor (java.lang.reflect.Constructor)1 Type (java.lang.reflect.Type)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 List (java.util.List)1 JSONArray (org.json.JSONArray)1 JSONException (org.json.JSONException)1