public void testUnionStructObjectInspector() throws Throwable {
    try {
      ArrayList<String> fieldNames1 = new ArrayList<String>();
      fieldNames1.add("firstInteger");
      fieldNames1.add("secondString");
      fieldNames1.add("thirdBoolean");
      ArrayList<ObjectInspector> fieldObjectInspectors1 = new ArrayList<ObjectInspector>();
      fieldObjectInspectors1.add(PrimitiveObjectInspectorFactory.javaIntObjectInspector);
      fieldObjectInspectors1.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
      fieldObjectInspectors1.add(PrimitiveObjectInspectorFactory.javaBooleanObjectInspector);
      StandardStructObjectInspector soi1 =
          ObjectInspectorFactory.getStandardStructObjectInspector(
              fieldNames1, fieldObjectInspectors1);

      ArrayList<String> fieldNames2 = new ArrayList<String>();
      fieldNames2.add("fourthDouble");
      fieldNames2.add("fifthLong");
      ArrayList<ObjectInspector> fieldObjectInspectors2 = new ArrayList<ObjectInspector>();
      fieldObjectInspectors2.add(PrimitiveObjectInspectorFactory.javaDoubleObjectInspector);
      fieldObjectInspectors2.add(PrimitiveObjectInspectorFactory.javaLongObjectInspector);
      StandardStructObjectInspector soi2 =
          ObjectInspectorFactory.getStandardStructObjectInspector(
              fieldNames2, fieldObjectInspectors2);

      UnionStructObjectInspector usoi1 =
          ObjectInspectorFactory.getUnionStructObjectInspector(
              Arrays.asList(new StructObjectInspector[] {soi1, soi2}));
      UnionStructObjectInspector usoi2 =
          ObjectInspectorFactory.getUnionStructObjectInspector(
              Arrays.asList(new StructObjectInspector[] {soi1, soi2}));

      assertEquals(usoi1, usoi2);

      // metadata
      assertEquals(Category.STRUCT, usoi1.getCategory());
      List<? extends StructField> fields = usoi1.getAllStructFieldRefs();
      assertEquals(5, fields.size());
      for (int i = 0; i < 5; i++) {
        if (i <= 2) {
          assertEquals(fieldNames1.get(i).toLowerCase(), fields.get(i).getFieldName());
          assertEquals(fieldObjectInspectors1.get(i), fields.get(i).getFieldObjectInspector());
        } else {
          assertEquals(fieldNames2.get(i - 3).toLowerCase(), fields.get(i).getFieldName());
          assertEquals(fieldObjectInspectors2.get(i - 3), fields.get(i).getFieldObjectInspector());
        }
      }
      assertEquals(fields.get(1), usoi1.getStructFieldRef("secondString"));
      assertEquals(fields.get(4), usoi1.getStructFieldRef("fifthLong"));

      // null
      for (int i = 0; i < 5; i++) {
        assertNull(usoi1.getStructFieldData(null, fields.get(i)));
      }

      // real struct
      ArrayList<Object> struct1 = new ArrayList<Object>(3);
      struct1.add(1);
      struct1.add("two");
      struct1.add(true);
      ArrayList<Object> struct2 = new ArrayList<Object>(2);
      struct2.add(1.0);
      struct2.add(new Long(111));
      ArrayList<Object> struct = new ArrayList<Object>(2);
      struct.add(struct1);
      struct.add(struct2);
      ArrayList<Object> all = new ArrayList<Object>(5);
      all.addAll(struct1);
      all.addAll(struct2);

      for (int i = 0; i < 5; i++) {
        assertEquals(all.get(i), usoi1.getStructFieldData(struct, fields.get(i)));
      }
    } catch (Throwable e) {
      e.printStackTrace();
      throw e;
    }
  }
 public static ObjectInspector getStandardObjectInspector(
     ObjectInspector oi, ObjectInspectorCopyOption objectInspectorOption) {
   ObjectInspector result = null;
   switch (oi.getCategory()) {
     case PRIMITIVE:
       {
         PrimitiveObjectInspector poi = (PrimitiveObjectInspector) oi;
         switch (objectInspectorOption) {
           case DEFAULT:
             {
               if (poi.preferWritable()) {
                 result =
                     PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(
                         poi.getTypeInfo());
               } else {
                 result =
                     PrimitiveObjectInspectorFactory.getPrimitiveJavaObjectInspector(
                         poi.getTypeInfo());
               }
               break;
             }
           case JAVA:
             {
               result =
                   PrimitiveObjectInspectorFactory.getPrimitiveJavaObjectInspector(
                       poi.getTypeInfo());
               break;
             }
           case WRITABLE:
             result =
                 PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(
                     poi.getTypeInfo());
             break;
         }
         break;
       }
     case LIST:
       {
         ListObjectInspector loi = (ListObjectInspector) oi;
         result =
             ObjectInspectorFactory.getStandardListObjectInspector(
                 getStandardObjectInspector(
                     loi.getListElementObjectInspector(), objectInspectorOption));
         break;
       }
     case MAP:
       {
         MapObjectInspector moi = (MapObjectInspector) oi;
         result =
             ObjectInspectorFactory.getStandardMapObjectInspector(
                 getStandardObjectInspector(moi.getMapKeyObjectInspector(), objectInspectorOption),
                 getStandardObjectInspector(
                     moi.getMapValueObjectInspector(), objectInspectorOption));
         break;
       }
     case STRUCT:
       {
         StructObjectInspector soi = (StructObjectInspector) oi;
         List<? extends StructField> fields = soi.getAllStructFieldRefs();
         List<String> fieldNames = new ArrayList<String>(fields.size());
         List<ObjectInspector> fieldObjectInspectors =
             new ArrayList<ObjectInspector>(fields.size());
         for (StructField f : fields) {
           fieldNames.add(f.getFieldName());
           fieldObjectInspectors.add(
               getStandardObjectInspector(f.getFieldObjectInspector(), objectInspectorOption));
         }
         result =
             ObjectInspectorFactory.getStandardStructObjectInspector(
                 fieldNames, fieldObjectInspectors);
         break;
       }
     case UNION:
       {
         UnionObjectInspector uoi = (UnionObjectInspector) oi;
         List<ObjectInspector> ois = new ArrayList<ObjectInspector>();
         for (ObjectInspector eoi : uoi.getObjectInspectors()) {
           ois.add(getStandardObjectInspector(eoi, objectInspectorOption));
         }
         result = ObjectInspectorFactory.getStandardUnionObjectInspector(ois);
         break;
       }
     default:
       {
         throw new RuntimeException("Unknown ObjectInspector category!");
       }
   }
   return result;
 }