in hollow/src/main/java/com/netflix/hollow/api/consumer/index/SelectFieldPathResultExtractor.java [72:154]
static <T> SelectFieldPathResultExtractor<T> from(
Class<? extends HollowAPI> apiType, HollowDataset dataset, Class<?> rootType, String fieldPath,
Class<T> selectType) {
String rootTypeName = HollowObjectTypeMapper.getDefaultTypeName(rootType);
FieldPaths.FieldPath<FieldPaths.FieldSegment> fp =
FieldPaths.createFieldPathForHashIndex(dataset, rootTypeName, fieldPath);
String typeName;
if (!fp.getSegments().isEmpty()) {
// @@@ Method on FieldPath
FieldPaths.FieldSegment lastSegment = fp.getSegments().get(fp.getSegments().size() - 1);
HollowSchema.SchemaType schemaType = lastSegment.getEnclosingSchema().getSchemaType();
HollowObjectSchema.FieldType schemaFieldType;
if (schemaType == HollowSchema.SchemaType.OBJECT) {
FieldPaths.ObjectFieldSegment os = (FieldPaths.ObjectFieldSegment) lastSegment;
schemaFieldType = os.getType();
} else {
schemaFieldType = HollowObjectSchema.FieldType.REFERENCE;
}
typeName = lastSegment.getTypeName();
if (schemaFieldType != HollowObjectSchema.FieldType.REFERENCE) {
// The field path must reference a field of a reference type
// This is contrary to the underlying HollowHashIndex which selects
// the enclosing reference type for a field of a value type.
// It is considered better to be consistent and literal with field path
// expressions
throw incompatibleSelectType(selectType, fieldPath, schemaFieldType);
} else if (typeName.equals("String")) {
if (!HollowObject.class.isAssignableFrom(selectType)) {
throw incompatibleSelectType(selectType, fieldPath, typeName);
}
// @@@ Check that object schema has single value field of String type such as HString
} else if (!HollowObjectTypeMapper.getDefaultTypeName(selectType).equals(typeName)) {
if (schemaType != HollowSchema.SchemaType.OBJECT && !GenericHollowObject.class.isAssignableFrom(
selectType)) {
throw incompatibleSelectType(selectType, fieldPath, typeName);
}
// @@@ GenericHollow{List, Set, Map} based on schemaType
} else if (!HollowRecord.class.isAssignableFrom(selectType)) {
throw incompatibleSelectType(selectType, fieldPath, typeName);
}
} else {
typeName = rootTypeName;
}
if (GenericHollowObject.class.isAssignableFrom(selectType)) {
BiObjectIntFunction<HollowAPI, T> extractor =
(a, o) -> {
@SuppressWarnings("unchecked")
T t = (T) new GenericHollowObject(a.getDataAccess(), typeName, o);
return t;
};
return new SelectFieldPathResultExtractor<>(fp, extractor);
} else {
MethodHandle selectInstantiate;
try {
selectInstantiate = MethodHandles.lookup().findVirtual(
apiType,
"get" + selectType.getSimpleName(),
MethodType.methodType(selectType, int.class));
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new IllegalArgumentException(
String.format("Select type %s is not associated with API %s",
selectType.getName(), apiType.getName()),
e);
}
BiObjectIntFunction<HollowAPI, T> extractor = (a, i) -> {
try {
@SuppressWarnings("unchecked")
T s = (T) selectInstantiate.invoke(a, i);
return s;
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable e) {
throw new RuntimeException(e);
}
};
return new SelectFieldPathResultExtractor<>(fp, extractor);
}
}