in hollow/src/main/java/com/netflix/hollow/api/consumer/index/MatchFieldPathArgumentExtractor.java [169:269]
static <Q, T> MatchFieldPathArgumentExtractor<Q> fromFunction(
HollowDataset dataset, Class<?> rootType, String fieldPath,
Class<T> extractorType, Function<Q, T> extractorFunction,
FieldPathResolver fpResolver) {
String rootTypeName = HollowObjectTypeMapper.getDefaultTypeName(rootType);
FieldPaths.FieldPath<? extends FieldPaths.FieldSegment> fp = fpResolver.resolve(dataset, rootTypeName,
fieldPath);
// @@@ Method on FieldPath
FieldPaths.FieldSegment lastSegment = fp.getSegments().get(fp.getSegments().size() - 1);
HollowObjectSchema.FieldType schemaFieldType;
if (lastSegment.getEnclosingSchema().getSchemaType() == HollowSchema.SchemaType.OBJECT) {
FieldPaths.ObjectFieldSegment os = (FieldPaths.ObjectFieldSegment) lastSegment;
schemaFieldType = os.getType();
} else {
schemaFieldType = HollowObjectSchema.FieldType.REFERENCE;
}
Function<Q, ?> extractor = extractorFunction;
switch (schemaFieldType) {
case BOOLEAN:
if (extractorType != boolean.class && extractorType != Boolean.class) {
throw incompatibleMatchType(extractorType, fieldPath, schemaFieldType);
}
break;
case DOUBLE:
if (extractorType != double.class && extractorType != Double.class) {
throw incompatibleMatchType(extractorType, fieldPath, schemaFieldType);
}
break;
case FLOAT:
if (extractorType != float.class && extractorType != Float.class) {
throw incompatibleMatchType(extractorType, fieldPath, schemaFieldType);
}
break;
case INT:
if (extractorType == byte.class || extractorType == Byte.class) {
@SuppressWarnings("unchecked")
Function<Q, Byte> f = (Function<Q, Byte>) extractorFunction;
extractor = f.andThen(Byte::intValue);
break;
} else if (extractorType == short.class || extractorType == Short.class) {
@SuppressWarnings("unchecked")
Function<Q, Short> f = (Function<Q, Short>) extractorFunction;
extractor = f.andThen(Short::intValue);
break;
} else if (extractorType == char.class || extractorType == Character.class) {
@SuppressWarnings("unchecked")
Function<Q, Character> f = (Function<Q, Character>) extractorFunction;
extractor = f.andThen(c -> (int) c);
} else if (extractorType != int.class && extractorType != Integer.class) {
throw incompatibleMatchType(extractorType, fieldPath, schemaFieldType);
}
break;
case LONG:
if (extractorType != long.class && extractorType != Long.class) {
throw incompatibleMatchType(extractorType, fieldPath, schemaFieldType);
}
break;
case REFERENCE: {
// @@@ If extractorType == int.class then consider it an ordinal value
// and directly use the extractorFunction
String typeName = lastSegment.getTypeName();
// Manage for String and all box types
if (typeName.equals("String")) {
if (!HollowObject.class.isAssignableFrom(extractorType)) {
throw incompatibleMatchType(extractorType, fieldPath, typeName);
}
// @@@ Check that object schema has single value field of String type such as HString
} else if (!extractorType.getSimpleName().equals(typeName)) {
throw incompatibleMatchType(extractorType, fieldPath, typeName);
} else if (!HollowRecord.class.isAssignableFrom(extractorType)) {
throw incompatibleMatchType(extractorType, fieldPath, typeName);
}
@SuppressWarnings("unchecked")
Function<Q, HollowRecord> f = (Function<Q, HollowRecord>) extractorFunction;
extractor = f.andThen(HollowRecord::getOrdinal);
break;
}
case BYTES:
if (extractorType != byte[].class) {
throw incompatibleMatchType(extractorType, fieldPath, schemaFieldType);
}
break;
case STRING:
if (extractorType == char[].class) {
@SuppressWarnings("unchecked")
Function<Q, char[]> f = (Function<Q, char[]>) extractorFunction;
extractor = f.andThen(String::valueOf);
break;
} else if (extractorType != String.class) {
throw incompatibleMatchType(extractorType, fieldPath, schemaFieldType);
}
break;
}
return new MatchFieldPathArgumentExtractor<>(fp, extractor);
}