예제 #1
0
 private static Constructor fullConstructor(Class klass) {
   Constructor[] array = klass.getConstructors();
   for (Constructor constructor : array) {
     if (constructor.isAnnotationPresent(FullConstructor.class)) {
       return constructor;
     }
   }
   return null;
 }
예제 #2
0
  // load all reference types that are possible to instantiate
  // using FullConstructor annotation
  private Map<String, Class> loadTypeMap() throws ClassNotFoundException {
    Class[] classes = {

      // common classes
      PartySelf.class,
      Archetyped.class,
      Attestation.class,
      AuditDetails.class,
      Participation.class,
      PartyIdentified.class,
      PartyRelated.class,
      PartySelf.class,
      OriginalVersion.class,
      Contribution.class,

      // support classes
      TerminologyID.class,
      ArchetypeID.class,
      HierObjectID.class,
      AccessGroupRef.class,
      GenericID.class,
      InternetID.class,
      ISO_OID.class,
      LocatableRef.class,
      ObjectVersionID.class,
      ObjectRef.class,
      PartyRef.class,
      TemplateID.class,
      TerminologyID.class,
      org.openehr.rm.support.identification.UUID.class,
      // VersionTreeID.class,

      // datatypes classes
      DvBoolean.class,
      DvState.class,
      DvIdentifier.class,
      DvText.class,
      DvCodedText.class,
      DvParagraph.class,
      CodePhrase.class,
      DvCount.class,
      DvOrdinal.class,
      DvQuantity.class,
      DvInterval.class,
      DvProportion.class,
      DvDate.class,
      DvDateTime.class,
      DvTime.class,
      DvDuration.class,
      DvParsable.class,
      DvURI.class,
      DvEHRURI.class,
      DvMultimedia.class,

      // datastructure classes
      Element.class,
      Cluster.class,
      ItemSingle.class,
      ItemList.class,
      ItemTable.class,
      ItemTree.class,
      // ItemStructure.class,
      History.class,
      IntervalEvent.class,
      PointEvent.class,

      // ehr classes
      Action.class,
      Activity.class,
      Evaluation.class,
      ISMTransition.class,
      Instruction.class,
      InstructionDetails.class,
      Observation.class,
      AdminEntry.class,
      Section.class,
      Composition.class,
      EventContext.class,
      ISMTransition.class,

      // demographic classes
      Address.class,
      PartyIdentity.class,
      Agent.class,
      Group.class,
      Organisation.class,
      Person.class,
      Contact.class,
      PartyRelationship.class,
      Role.class,
      Capability.class
    };

    typeMap = new HashMap<String, Class>();
    upperCaseMap = new HashMap<String, Class>();
    for (Class klass : classes) {
      String name = klass.getSimpleName();
      typeMap.put(name, klass);
      upperCaseMap.put(name.toUpperCase(), klass);
    }

    return typeMap;
  }
예제 #3
0
  /**
   * Finds the matching RM class that can be used to create RM object for given value map
   *
   * @param valueMap
   * @return null if no match RM class is found
   */
  public String findMatchingRMClass(Map<String, Object> valueMap) {
    List simpleTypes = Arrays.asList(SKIPPED_TYPES_IN_MATCHING);

    for (Class rmClass : typeMap.values()) {

      log.debug("matching rmClass: " + rmClass.getName());

      if (simpleTypes.contains(rmClass.getSimpleName())) {
        continue; // skip simple value types
      }

      // replace underscore separated names with camel case
      Map<String, Object> filteredMap = new HashMap<String, Object>();
      for (String name : valueMap.keySet()) {
        filteredMap.put(toCamelCase(name), valueMap.get(name));
      }

      Constructor constructor = fullConstructor(rmClass);
      if (constructor == null) {
        throw new RuntimeException("annotated constructor missing for " + rmClass);
      }
      Annotation[][] annotations = constructor.getParameterAnnotations();
      if (annotations == null || annotations.length == 0) {
        throw new RuntimeException("attribute annotations missing for " + rmClass);
      }
      Class[] types = constructor.getParameterTypes();
      boolean matched = true;
      Set<String> attributes = new HashSet<String>();

      for (int i = 0; i < types.length; i++) {
        if (annotations[i].length == 0) {
          throw new RuntimeException("attribute annotation missing for" + rmClass);
        }
        Attribute attribute = (Attribute) annotations[i][0];
        attributes.add(attribute.name());

        log.debug("checking attribute: " + attribute.name());

        String attrName = attribute.name();
        Object attrValue = filteredMap.get(attrName);

        if (attribute.required() && attrValue == null) {

          log.debug("missing required attribute..");

          matched = false;
          break;

        } else if (attrValue != null) {
          if (((attrValue instanceof Boolean) && types[i] != boolean.class)
              || ((attrValue instanceof Integer) && types[i] != Integer.class)
              || ((attrValue instanceof Double) && types[i] != double.class)) {

            log.debug("wrong primitive value type for attribute..");
            matched = false;
            break;

          } else if (!types[i].isPrimitive() && !types[i].isInstance(attrValue)) {
            log.debug("wrong value type for attribute..");
            matched = false;
            break;
          }
        }
      }

      for (String attr : filteredMap.keySet()) {
        if (!attributes.contains(attr)) {

          log.debug("unknown attribute: " + attr);

          matched = false;
        }
      }

      // matching found
      if (matched) {
        String className = rmClass.getSimpleName();

        log.debug(">>> MATCHING FOUND: " + className);

        return className;
      }
    }
    return null;
  }
예제 #4
0
  /**
   * Construct an instance of RM class of given name and values.
   *
   * <p>If the input is a string, and the required attribute is some other types (integer, double
   * etc), it will be converted into right type. if there is any error during conversion,
   * AttributeFormatException will be thrown.
   *
   * @param rmClassName
   * @param valueMap
   * @return created instance
   * @throws RMObjectBuildingException
   */
  public RMObject construct(String rmClassName, Map<String, Object> valueMap)
      throws RMObjectBuildingException {

    Class rmClass = retrieveRMType(rmClassName);

    // replace underscore separated names with camel case
    Map<String, Object> filteredMap = new HashMap<String, Object>();
    for (String name : valueMap.keySet()) {
      filteredMap.put(toCamelCase(name), valueMap.get(name));
    }
    Constructor constructor = fullConstructor(rmClass);
    Map<String, Class> typeMap = attributeType(rmClass);
    Map<String, Integer> indexMap = attributeIndex(rmClass);
    Map<String, Attribute> attributeMap = attributeMap(rmClass);
    Object[] valueArray = new Object[indexMap.size()];

    for (String name : typeMap.keySet()) {

      Object value = filteredMap.get(name);

      if (!typeMap.containsKey(name) || !attributeMap.containsKey(name)) {
        throw new RMObjectBuildingException("unknown attribute " + name);
      }

      Class type = typeMap.get(name);
      Integer index = indexMap.get(name);

      Attribute attribute = attributeMap.get(name);
      if (index == null || type == null) {
        throw new RMObjectBuildingException("unknown attribute \"" + name + "\"");
      }

      // system supplied value
      if (attribute.system()) {
        SystemValue sysvalue = SystemValue.fromId(name);
        if (sysvalue == null) {
          throw new RMObjectBuildingException("unknonw system value" + "\"" + name + "\"");
        }
        value = systemValues.get(sysvalue);
        if (value == null) {
          throw new AttributeMissingException(
              "missing value for "
                  + "system attribute \""
                  + name
                  + "\" in class: "
                  + rmClass
                  + ", with valueMap: "
                  + valueMap);
        }
      }

      // check required attributes
      if (value == null && attribute.required()) {
        log.info(attribute);
        throw new AttributeMissingException(
            "missing value for "
                + "required attribute \""
                + name
                + "\" of type "
                + type
                + " while constructing "
                + rmClass
                + " with valueMap: "
                + valueMap);
      }

      // enum
      else if (type.isEnum() && !value.getClass().isEnum()) {
        // OG added
        if (type.equals(ProportionKind.class))
          value = ProportionKind.fromValue(Integer.parseInt(value.toString()));
        else value = Enum.valueOf(type, value.toString());
      }

      // in case of null, create a default value
      else if (value == null) {
        value = defaultValue(type);
      }

      // in case of string value, convert to right type if necessary
      else if (value instanceof String) {
        String str = (String) value;
        try {

          // for DvCount
          if (type.equals(int.class)) {
            value = Integer.parseInt(str);

            // for DvQuantity
          } else if (type.equals(double.class)) {
            value = Double.parseDouble(str);

            // for DvProportion.precision
          } else if (type.equals(Integer.class)) {
            value = new Integer(str);
          }

        } catch (NumberFormatException e) {
          throw new AttributeFormatException(
              "wrong format of " + "attribute " + name + ", expect " + type);
        }

        // deal with mismatch between array and list
      } else if (type.isAssignableFrom(List.class) && value.getClass().isArray()) {

        Object[] array = (Object[]) value;
        List list = new ArrayList();
        for (Object o : array) {
          list.add(o);
        }
        value = list;

        // deal with mismatch between array and set
      } else if (type.isAssignableFrom(Set.class) && value.getClass().isArray()) {

        Object[] array = (Object[]) value;
        Set set = new HashSet();
        for (Object o : array) {
          set.add(o);
        }
        value = set;
      }
      // check type
      else if (value != null && !type.isPrimitive()) {
        try {
          type.cast(value);
        } catch (ClassCastException e) {
          throw new RMObjectBuildingException(
              "Failed to construct: "
                  + rmClassName
                  + ", value for attribute '"
                  + name
                  + "' has wrong type, expected \""
                  + type
                  + "\", but got \""
                  + value.getClass()
                  + "\"");
        }
      }
      valueArray[index] = value;
    }

    Object ret = null;
    try {
      // OG added hack
      if (rmClassName.equalsIgnoreCase("DVCOUNT")) {
        log.debug("Fixing DVCOUNT...");
        for (int i = 0; i < valueArray.length; i++) {
          Object value = valueArray[i];
          if (value != null && value.getClass().equals(Float.class))
            valueArray[i] = Double.parseDouble(value.toString());
          else if (value != null && value.getClass().equals(Long.class))
            valueArray[i] = Integer.parseInt(value.toString());
        }
      }
      ret = constructor.newInstance(valueArray);
    } catch (Exception e) {

      if (log.isDebugEnabled()) {
        e.printStackTrace();
      }

      log.debug("failed in constructor.newInstance()", e);

      if (stringParsingTypes.contains(rmClassName)) {
        throw new AttributeFormatException("wrong format for type " + rmClassName);
      }

      throw new RMObjectBuildingException(
          "failed to create new instance of  "
              + rmClassName
              + " with valueMap: "
              + toString(valueMap)
              + ", cause: "
              + e.getMessage());
    }
    return (RMObject) ret;
  }