TupleSchema { public static TupleSchema of(String name, TupleSlot...slots) { if (name == null) throw new IllegalArgumentException("name must not be null"); if (slots == null) throw new IllegalArgumentException("slots must not be null"); Map<String, Integer> slotLookup = IntStream.range(0, slots.length) .collect(HashMap::new, (m, i) -> m.put(slots[i].getName(), i), Map::putAll); if (slots.length != slotLookup.size()) throw new IllegalArgumentException("Slot names are not unique"); return new TupleSchema(name, slots, slotLookup); } private  TupleSchema(String name, TupleSlot[] slots, Map<String, Integer> slotLookup); static TupleSchema of(String name, TupleSlot...slots); String getName(); Tuple makeWith(Object...values); Tuple make(Object[] values); Tuple make(TupleKeyValue...keyValues); Tuple make(NamedValue...builders); Tuple make(Map<String, Object> values); Tuple deserialise(BiFunction<V, Type, Object> deserialiser, Map<String, V> values); @Override boolean equals(Object o); @Override int hashCode(); @Override String toString(); TupleKey<Optional<T>> getOptionalKey(String name, Class<T> valueType); TupleKey<List<T>> getListKey(String name, Class<T> elementType); TupleKey<Map<K, V>> getMapKey(String name, Class<K> keyType, Class<V> valueType); TupleKey<T> getKey(String name, Type type);  }
@Test public void equality() { TupleSchema same = TupleSchema.of("coordinate", TupleSlot.of("x", Integer.class), TupleSlot.of("y", Integer.class)); TupleSchema different = TupleSchema.of("coordinate", TupleSlot.of("x", Integer.class), TupleSlot.of("z", Integer.class)); assertThat(coordinateSchema, equalTo(same)); assertThat(coordinateSchema, not(equalTo(different))); }