Schemas { public static <T> T visit(final Schema start, final SchemaVisitor<T> visitor) { IdentityHashSet<Schema> visited = new IdentityHashSet<>(); Deque<Object> dq = new ArrayDeque<>(); dq.addLast(start); Object current; while ((current = dq.pollLast()) != null) { if (current instanceof Supplier) { SchemaVisitorAction action = ((Supplier<SchemaVisitorAction>) current).get(); switch (action) { case CONTINUE: break; case SKIP_SUBTREE: throw new UnsupportedOperationException(); case SKIP_SIBLINGS: while (dq.getLast() instanceof Schema) { dq.removeLast(); } break; case TERMINATE: return visitor.get(); default: throw new UnsupportedOperationException("Invalid action " + action); } } else { Schema schema = (Schema) current; boolean terminate; if (!visited.contains(schema)) { Schema.Type type = schema.getType(); switch (type) { case ARRAY: terminate = visitNonTerminal(visitor, schema, dq, Collections.singletonList(schema.getElementType())); visited.add(schema); break; case RECORD: terminate = visitNonTerminal(visitor, schema, dq, Lists.transform(Lists.reverse(schema.getFields()), Field::schema)); visited.add(schema); break; case UNION: terminate = visitNonTerminal(visitor, schema, dq, schema.getTypes()); visited.add(schema); break; case MAP: terminate = visitNonTerminal(visitor, schema, dq, Collections.singletonList(schema.getValueType())); visited.add(schema); break; case NULL: case BOOLEAN: case BYTES: case DOUBLE: case ENUM: case FIXED: case FLOAT: case INT: case LONG: case STRING: terminate = visitTerminal(visitor, schema, dq); break; default: throw new UnsupportedOperationException("Invalid type " + type); } } else { terminate = visitTerminal(visitor, schema, dq); } if (terminate) { return visitor.get(); } } } return visitor.get(); } private  Schemas(); static void diff(final Schema s1, final Schema s2, final Consumer<SchemaDiff> diffs); @Nullable static Schema getFromUnion(final Schema what, final Schema unionSchema); static void deprecations(final Schema schema,
          final BiConsumer<String, String> toPut); @Nonnull static ImmutableSchema immutable(final Schema schema); @Nonnull static ImmutableSchema immutable(final Schema schema, final boolean withSerializationSignificatAttrsonly); static T visit(final Schema start, final SchemaVisitor<T> visitor); static boolean isNullableUnion(final Schema schema); @Nullable static Schema nullableUnionSchema(final Schema schema); @Nullable static Schema getSchemaFromUnionByName(final Schema unionSchema, final String name); @Nullable static Schema getSubSchema(final Schema schema, final CharSequence path); static Schema projectRecord(final Schema schema, final int[] projection); @Nullable static Schema project(final Schema schema, final CharSequence... paths); @Nullable static Schema project(final Schema schema, final List<? extends CharSequence> paths); static boolean isSameFields(final List<Schema.Field> f1s, final List<Schema.Field> f2s); @Nullable static IndexedRecord project(final Schema toSchema, final Schema fromSchema,
          @Nullable final IndexedRecord object); @Nullable @SuppressFBWarnings("URV_UNRELATED_RETURN_VALUES") static Object project(final Schema toSchema, final Schema fromSchema, @Nullable final Object object); @Nullable static Schema.Field getPos(final Schema.Field field, final Schema recordSchema); @Nullable static Schema.Field getField(final String name, final Iterable<Field> fields); static boolean isNamed(final String name, final Field field); static Schema dateString(); static Schema instantString(); static Schema temporalString();  }
@Test public void testVisit() throws IOException { Schema recSchema = new Schema.Parser().parse(SCHEMA); Schemas.visit(recSchema, new PrintingVisitor()); String schemaStr = Resources.toString(Resources.getResource("SchemaBuilder.avsc"), StandardCharsets.US_ASCII); Schema schema = new Schema.Parser().parse(schemaStr); Map<String, Schema> schemas = Schemas.visit(schema, new SchemasWithClasses()); Assert.assertThat(schemas, Matchers.hasValue(schema)); Schema trimmed = Schemas.visit(recSchema, new CloningVisitor(recSchema)); Assert.assertNull(trimmed.getDoc()); Assert.assertNotNull(recSchema.getDoc()); SchemaCompatibility.SchemaCompatibilityType compat = SchemaCompatibility.checkReaderWriterCompatibility(trimmed, recSchema).getType(); Assert.assertEquals(SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE, compat); compat = SchemaCompatibility.checkReaderWriterCompatibility(recSchema, trimmed).getType(); Assert.assertEquals(SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE, compat); Schema unmodifyable = Schemas.visit(recSchema, new ImmutableCloningVisitor(recSchema, false)); Assert.assertNotNull(unmodifyable.getDoc()); compat = SchemaCompatibility.checkReaderWriterCompatibility(unmodifyable, recSchema).getType(); Assert.assertEquals(SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE, compat); compat = SchemaCompatibility.checkReaderWriterCompatibility(recSchema, unmodifyable).getType(); Assert.assertEquals(SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE, compat); Schema schema1 = unmodifyable.getField("subNodes").schema().getElementType().getField("node").schema(); try { schema1.addAlias("yahooo"); Assert.fail(); } catch (UnsupportedOperationException ex) { } try { schema1.setFields(Collections.EMPTY_LIST); Assert.fail(); } catch (UnsupportedOperationException ex) { } }