public static boolean validate(Schema schema, Object datum) {
      switch (schema.getType()) {
         case RECORD:
            if (datum instanceof GenericRecord) {
               GenericRecord record = (GenericRecord) datum;
               for (Schema.Field f : schema.getFields()) {
                  if (!record.hasField(f.name()))
                     return false;
                  if (!validate(f.schema(), record.get(f.pos())))
                     return false;
               }
               return true;
            }
         default:
            return GenericData.get().validate(schema, datum);
      }
   }
@Test
   void testValidate() {
      Schema v1Schema = SchemaBuilder.record("User").fields().requiredString("name").requiredInt("age").endRecord();
      Schema v2Schema = SchemaBuilder.record("User").fields().requiredString("fullName").requiredInt("age")
            .optionalString("email").endRecord();

      GenericRecord userv1 = new GenericData.Record(v1Schema);
      userv1.put("name", "Laurent");
      userv1.put("age", 42);

      assertFalse(AvroUtil.validate(v2Schema, userv1));
      // The Avro validate method fails because it does not validate the field name
      // just the position. This make it not usable in our context.
      //assertFalse(GenericData.get().validate(v2Schema, userv1));

      List<String> errors = AvroUtil.getValidationErrors(v2Schema, userv1);
      assertEquals(1, errors.size());
      assertEquals("Required field fullName cannot be found in record", errors.get(0));

      GenericRecord userv2 = new GenericData.Record(v2Schema);
      userv2.put("fullName", "Laurent Broudoux");
      userv2.put("age", 42);

      assertTrue(AvroUtil.validate(v2Schema, userv2));
   }