protected List<ValidationException> testField(
      Type type, SegmentType.Field profile, boolean escape) {
    List<ValidationException> exList = new ArrayList<>();

    UsageInfo usage = new UsageInfo(profile);

    // account for MSH 1 & 2 which aren't escaped
    String encoded = null;
    if (!escape && Primitive.class.isAssignableFrom(type.getClass()))
      encoded = ((Primitive) type).getValue();

    exList.addAll(testType(type, profile.getDatatype(), usage, encoded, false));

    // test children
    if (validateChildren) {
      if (profile.getComponents().size() > 0 && !usage.disallowed()) {
        if (Composite.class.isAssignableFrom(type.getClass())) {
          Composite comp = (Composite) type;
          int i = 1;
          boolean nullContext = false;
          for (SegmentType.Field.Component component : profile.getComponents()) {
            try {
              SegmentType.Field.Component component2;
              if (nullContext) {
                component2 = new SegmentType.Field.Component();
                try {
                  BeanUtils.copyProperties(component2, component);
                } catch (InvocationTargetException | IllegalAccessException e) {
                  // nop
                }
                component2.setUsage("NULL");
              } else {
                component2 = component;
                if ((i == 1)
                    && profile.isNullable()
                    && PipeParser.encode(comp.getComponent(0), this.enc).equals("\"\"")) {
                  nullContext = true;
                }
              }

              exList.addAll(testComponent(comp.getComponent(i - 1), component2));
            } catch (DataTypeException de) {
              profileNotHL7Compliant(exList, COMPONENT_TYPE_MISMATCH, type.getName(), i);
            }
            ++i;
          }
          exList.addAll(checkUndefinedComponents(comp, profile.getComponents().size()));
        } else {
          profileNotHL7Compliant(exList, WRONG_FIELD_TYPE, type.getClass().getName());
        }
      }
    }
    return exList;
  }
 // Work around HAPI #224: TSComponentOne implementation of isEmpty is buggy
 private static boolean isEmpty(Visitable v) throws HL7Exception {
   if (v == null) return true;
   if (v instanceof TSComponentOne) {
     TSComponentOne tsc1 = (TSComponentOne) v;
     return tsc1.getValue() == null || tsc1.getValue().isEmpty();
   }
   if (v instanceof Composite && v.getClass().getName().endsWith(".TS")) {
     Composite ts = (Composite) v;
     return isEmpty(ts.getComponent(0));
   }
   return v.isEmpty();
 }
  /** Tests for extra components (i.e. any not defined in the profile) */
  protected List<ValidationException> checkUndefinedComponents(Composite comp, int numInProfile) {
    List<ValidationException> exList = new ArrayList<>();

    StringBuilder extra = new StringBuilder();
    for (int i = numInProfile; i < comp.getComponents().length; i++) {
      try {
        String s = comp.getComponent(i).encode();
        if (s.length() > 0) {
          extra.append(s).append(enc.getComponentSeparator());
        }
      } catch (HL7Exception de) {
        exList.add(new ValidationException(de));
      }
    }
    profileViolatedWhen(
        extra.toString().length() > 0, exList, COMPONENT_NOT_DEFINED_IN_PROFILE, extra.toString());

    return exList;
  }
  protected List<ValidationException> testComponent(
      Type type, SegmentType.Field.Component profile) {
    List<ValidationException> exList = new ArrayList<>();
    UsageInfo usage = new UsageInfo(profile);
    exList.addAll(testType(type, profile.getDatatype(), usage, null));

    // test children
    try {
      if (profile.getSubComponents().size() > 0 && !usage.disallowed() && !isEmpty(type)) {
        if (Composite.class.isAssignableFrom(type.getClass())) {
          Composite comp = (Composite) type;

          if (validateChildren) {
            int i = 1;
            for (SegmentType.Field.Component.SubComponent subComponent :
                profile.getSubComponents()) {
              UsageInfo scUsage = new UsageInfo(subComponent);
              try {
                Type sub = comp.getComponent(i - 1);
                exList.addAll(testType(sub, subComponent.getDatatype(), scUsage, null));
              } catch (DataTypeException de) {
                profileNotHL7Compliant(exList, SUBCOMPONENT_TYPE_MISMATCH, type.getName(), i);
              }
              ++i;
            }
          }

          exList.addAll(checkUndefinedComponents(comp, profile.getSubComponents().size()));
        } else {
          profileViolatedWhen(true, exList, WRONG_COMPONENT_TYPE, type.getClass().getName());
        }
      }
    } catch (HL7Exception e) {
      exList.add(new ValidationException(e));
    }

    return exList;
  }
 protected String msg(String prefix, Composite element, int component, String path) {
   String reference = getSectionReference();
   String elementType = element.getClass().getSimpleName();
   return "Validation error: "
       + ((reference == null) ? ("rule for type " + elementType) : reference)
       + " : "
       + prefix
       + " of type "
       + elementType
       + ", component "
       + component
       + ", path "
       + path;
 }