hollow/src/main/java/com/netflix/hollow/core/index/FieldPaths.java
static FieldPath<FieldSegment> createFieldPath(
            HollowDataset dataset, String type, String path,
            boolean autoExpand, boolean requireFullPath, boolean traverseSequences) {
        Objects.requireNonNull(dataset);
        Objects.requireNonNull(type);
        Objects.requireNonNull(path);

        String[] segments = path.isEmpty() ? new String[0] : path.split("\\.");
        List<FieldSegment> fieldSegments = new ArrayList<>();

        String segmentType = type;
        for (int i = 0; i < segments.length; i++) {
            HollowSchema schema = dataset.getSchema(segmentType);
            // @@@ Can this only occur for anything other than the root `type`?
            if (schema == null) {
                throw new FieldPathException(FieldPathException.ErrorKind.NOT_BINDABLE, dataset, type, segments,
                        fieldSegments, null, i);
            }

            String segment = segments[i];
            HollowSchema.SchemaType schemaType = schema.getSchemaType();
            if (schemaType == HollowSchema.SchemaType.OBJECT) {
                HollowObjectSchema objectSchema = (HollowObjectSchema) schema;

                int index = objectSchema.getPosition(segment);
                if (index == -1) {
                    throw new FieldPathException(FieldPathException.ErrorKind.NOT_FOUND, dataset, type, segments,
                            fieldSegments, schema, i);
                }

                segmentType = objectSchema.getReferencedType(index);
                fieldSegments.add(new ObjectFieldSegment(objectSchema, segment, segmentType, index));
            } else if (traverseSequences && (schemaType == HollowSchema.SchemaType.SET
                    || schemaType == HollowSchema.SchemaType.LIST)) {
                HollowCollectionSchema collectionSchema = (HollowCollectionSchema) schema;

                if (!segment.equals("element")) {
                    throw new FieldPathException(FieldPathException.ErrorKind.NOT_FOUND, dataset, type, segments,
                            fieldSegments, schema, i);
                }

                segmentType = collectionSchema.getElementType();
                fieldSegments.add(new FieldSegment(collectionSchema, segment, segmentType));
            } else if (traverseSequences && schemaType == HollowSchema.SchemaType.MAP) {
                HollowMapSchema mapSchema = (HollowMapSchema) schema;

                if (segment.equals("key")) {
                    segmentType = mapSchema.getKeyType();
                } else if (segment.equals("value")) {
                    segmentType = mapSchema.getValueType();
                } else {
                    throw new FieldPathException(FieldPathException.ErrorKind.NOT_FOUND, dataset, type, segments,
                            fieldSegments, schema, i);
                }

                fieldSegments.add(new FieldSegment(mapSchema, segment, segmentType));
            } else if (!traverseSequences) {
                throw new FieldPathException(FieldPathException.ErrorKind.NOT_TRAVERSABLE, dataset, type, segments,
                        fieldSegments, schema, i);
            }

            if (i < segments.length - 1 && segmentType == null) {
                throw new FieldPathException(FieldPathException.ErrorKind.NOT_TRAVERSABLE, dataset, type, segments,
                        fieldSegments, schema, i);
            }
        }

        if (autoExpand) {
            while (segmentType != null) {
                HollowSchema schema = dataset.getSchema(segmentType);

                if (schema.getSchemaType() == HollowSchema.SchemaType.OBJECT) {
                    HollowObjectSchema objectSchema = (HollowObjectSchema) schema;

                    if (objectSchema.numFields() == 1) {
                        segmentType = objectSchema.getReferencedType(0);

                        fieldSegments.add(
                                new ObjectFieldSegment(objectSchema, objectSchema.getFieldName(0), segmentType,
                                        0));
                    } else if (objectSchema.getPrimaryKey() != null && objectSchema.getPrimaryKey().numFields() == 1) {
                        PrimaryKey key = objectSchema.getPrimaryKey();

                        FieldPath<ObjectFieldSegment> expandedFieldSegments;
                        try {
                            expandedFieldSegments =
                                    createFieldPathForPrimaryKey(dataset, key.getType(), key.getFieldPaths()[0]);
                        } catch (FieldPathException cause) {
                            FieldPathException e = new FieldPathException(FieldPathException.ErrorKind.NOT_EXPANDABLE,
                                    dataset, type, segments,
                                    fieldSegments, objectSchema);
                            e.initCause(cause);
                            throw e;
                        }

                        fieldSegments.addAll(expandedFieldSegments.segments);
                        break;
                    } else {
                        throw new FieldPathException(FieldPathException.ErrorKind.NOT_EXPANDABLE, dataset, type,
                                segments,
                                fieldSegments, objectSchema);
                    }
                } else {
                    throw new FieldPathException(FieldPathException.ErrorKind.NOT_EXPANDABLE, dataset, type, segments,
                            fieldSegments, schema);
                }
            }
        } else if (requireFullPath && segmentType != null) {
            throw new FieldPathException(FieldPathException.ErrorKind.NOT_FULL, dataset, type, segments,
                    fieldSegments);
        }

        return new FieldPath<>(type, fieldSegments, !autoExpand);
    }
static FieldPath<FieldSegment> createFieldPath(
            HollowDataset dataset, String type, String path,
            boolean autoExpand, boolean requireFullPath, boolean traverseSequences) {
        Objects.requireNonNull(dataset);
        Objects.requireNonNull(type);
        Objects.requireNonNull(path);

        String[] segments = path.isEmpty() ? new String[0] : path.split("\\.");
        List<FieldSegment> fieldSegments = new ArrayList<>();

        String segmentType = type;
        for (int i = 0; i < segments.length; i++) {
            HollowSchema schema = dataset.getSchema(segmentType);
            // @@@ Can this only occur for anything other than the root `type`?
            if (schema == null) {
                throw new FieldPathException(FieldPathException.ErrorKind.NOT_BINDABLE, dataset, type, segments,
                        fieldSegments, null, i);
            }

            String segment = segments[i];
            HollowSchema.SchemaType schemaType = schema.getSchemaType();
            if (schemaType == HollowSchema.SchemaType.OBJECT) {
                HollowObjectSchema objectSchema = (HollowObjectSchema) schema;

                int index = objectSchema.getPosition(segment);
                if (index == -1) {
                    throw new FieldPathException(FieldPathException.ErrorKind.NOT_FOUND, dataset, type, segments,
                            fieldSegments, schema, i);
                }

                segmentType = objectSchema.getReferencedType(index);
                fieldSegments.add(new ObjectFieldSegment(objectSchema, segment, segmentType, index));
            } else if (traverseSequences && (schemaType == HollowSchema.SchemaType.SET
                    || schemaType == HollowSchema.SchemaType.LIST)) {
                HollowCollectionSchema collectionSchema = (HollowCollectionSchema) schema;

                if (!segment.equals("element")) {
                    throw new FieldPathException(FieldPathException.ErrorKind.NOT_FOUND, dataset, type, segments,
                            fieldSegments, schema, i);
                }

                segmentType = collectionSchema.getElementType();
                fieldSegments.add(new FieldSegment(collectionSchema, segment, segmentType));
            } else if (traverseSequences && schemaType == HollowSchema.SchemaType.MAP) {
                HollowMapSchema mapSchema = (HollowMapSchema) schema;

                if (segment.equals("key")) {
                    segmentType = mapSchema.getKeyType();
                } else if (segment.equals("value")) {
                    segmentType = mapSchema.getValueType();
                } else {
                    throw new FieldPathException(FieldPathException.ErrorKind.NOT_FOUND, dataset, type, segments,
                            fieldSegments, schema, i);
                }

                fieldSegments.add(new FieldSegment(mapSchema, segment, segmentType));
            } else if (!traverseSequences) {
                throw new FieldPathException(FieldPathException.ErrorKind.NOT_TRAVERSABLE, dataset, type, segments,
                        fieldSegments, schema, i);
            }

            if (i < segments.length - 1 && segmentType == null) {
                throw new FieldPathException(FieldPathException.ErrorKind.NOT_TRAVERSABLE, dataset, type, segments,
                        fieldSegments, schema, i);
            }
        }

        if (autoExpand) {
            while (segmentType != null) {
                HollowSchema schema = dataset.getSchema(segmentType);

                if (schema.getSchemaType() == HollowSchema.SchemaType.OBJECT) {
                    HollowObjectSchema objectSchema = (HollowObjectSchema) schema;

                    if (objectSchema.numFields() == 1) {
                        segmentType = objectSchema.getReferencedType(0);

                        fieldSegments.add(
                                new ObjectFieldSegment(objectSchema, objectSchema.getFieldName(0), segmentType,
                                        0));
                    } else if (objectSchema.getPrimaryKey() != null && objectSchema.getPrimaryKey().numFields() == 1) {
                        PrimaryKey key = objectSchema.getPrimaryKey();

                        FieldPath<ObjectFieldSegment> expandedFieldSegments;
                        try {
                            expandedFieldSegments =
                                    createFieldPathForPrimaryKey(dataset, key.getType(), key.getFieldPaths()[0]);
                        } catch (FieldPathException cause) {
                            FieldPathException e = new FieldPathException(FieldPathException.ErrorKind.NOT_EXPANDABLE,
                                    dataset, type, segments,
                                    fieldSegments, objectSchema);
                            e.initCause(cause);
                            throw e;
                        }

                        fieldSegments.addAll(expandedFieldSegments.segments);
                        break;
                    } else {
                        throw new FieldPathException(FieldPathException.ErrorKind.NOT_EXPANDABLE, dataset, type,
                                segments,
                                fieldSegments, objectSchema);
                    }
                } else {
                    throw new FieldPathException(FieldPathException.ErrorKind.NOT_EXPANDABLE, dataset, type, segments,
                            fieldSegments, schema);
                }
            }
        } else if (requireFullPath && segmentType != null) {
            throw new FieldPathException(FieldPathException.ErrorKind.NOT_FULL, dataset, type, segments,
                    fieldSegments);
        }

        return new FieldPath<>(type, fieldSegments, !autoExpand);
    }
static FieldPath < FieldSegment > createFieldPath ( HollowDataset dataset , String type , String path , boolean autoExpand , boolean requireFullPath , boolean traverseSequences ) { Objects . requireNonNull ( dataset ) ; Objects . requireNonNull ( type ) ; Objects . requireNonNull ( path ) ; String [ ] segments = path . isEmpty ( ) ? new String [ 0 ] : path . split ( "\\." ) ; List < FieldSegment > fieldSegments = new ArrayList <> ( ) ; String segmentType = type ; for ( int i = 0 ; i < segments . length ; i ++ ) { HollowSchema schema = dataset . getSchema ( segmentType ) ; // @@@ Can this only occur for anything other than the root `type`? if ( schema == null ) { throw new FieldPathException ( FieldPathException . ErrorKind . NOT_BINDABLE , dataset , type , segments , fieldSegments , null , i ) ; } String segment = segments [ i ] ; HollowSchema . SchemaType schemaType = schema . getSchemaType ( ) ; if ( schemaType == HollowSchema . SchemaType . OBJECT ) { HollowObjectSchema objectSchema = ( HollowObjectSchema ) schema ; int index = objectSchema . getPosition ( segment ) ; if ( index == - 1 ) { throw new FieldPathException ( FieldPathException . ErrorKind . NOT_FOUND , dataset , type , segments , fieldSegments , schema , i ) ; } segmentType = objectSchema . getReferencedType ( index ) ; fieldSegments . add ( new ObjectFieldSegment ( objectSchema , segment , segmentType , index ) ) ; } else if ( traverseSequences && ( schemaType == HollowSchema . SchemaType . SET || schemaType == HollowSchema . SchemaType . LIST ) ) { HollowCollectionSchema collectionSchema = ( HollowCollectionSchema ) schema ; if ( ! segment . equals ( "element" ) ) { throw new FieldPathException ( FieldPathException . ErrorKind . NOT_FOUND , dataset , type , segments , fieldSegments , schema , i ) ; } segmentType = collectionSchema . getElementType ( ) ; fieldSegments . add ( new FieldSegment ( collectionSchema , segment , segmentType ) ) ; } else if ( traverseSequences && schemaType == HollowSchema . SchemaType . MAP ) { HollowMapSchema mapSchema = ( HollowMapSchema ) schema ; if ( segment . equals ( "key" ) ) { segmentType = mapSchema . getKeyType ( ) ; } else if ( segment . equals ( "value" ) ) { segmentType = mapSchema . getValueType ( ) ; } else { throw new FieldPathException ( FieldPathException . ErrorKind . NOT_FOUND , dataset , type , segments , fieldSegments , schema , i ) ; } fieldSegments . add ( new FieldSegment ( mapSchema , segment , segmentType ) ) ; } else if ( ! traverseSequences ) { throw new FieldPathException ( FieldPathException . ErrorKind . NOT_TRAVERSABLE , dataset , type , segments , fieldSegments , schema , i ) ; } if ( i < segments . length - 1 && segmentType == null ) { throw new FieldPathException ( FieldPathException . ErrorKind . NOT_TRAVERSABLE , dataset , type , segments , fieldSegments , schema , i ) ; } } if ( autoExpand ) { while ( segmentType != null ) { HollowSchema schema = dataset . getSchema ( segmentType ) ; if ( schema . getSchemaType ( ) == HollowSchema . SchemaType . OBJECT ) { HollowObjectSchema objectSchema = ( HollowObjectSchema ) schema ; if ( objectSchema . numFields ( ) == 1 ) { segmentType = objectSchema . getReferencedType ( 0 ) ; fieldSegments . add ( new ObjectFieldSegment ( objectSchema , objectSchema . getFieldName ( 0 ) , segmentType , 0 ) ) ; } else if ( objectSchema . getPrimaryKey ( ) != null && objectSchema . getPrimaryKey ( ) . numFields ( ) == 1 ) { PrimaryKey key = objectSchema . getPrimaryKey ( ) ; FieldPath < ObjectFieldSegment > expandedFieldSegments ; try { expandedFieldSegments = createFieldPathForPrimaryKey ( dataset , key . getType ( ) , key . getFieldPaths ( ) [ 0 ] ) ; } catch ( FieldPathException cause ) { FieldPathException e = new FieldPathException ( FieldPathException . ErrorKind . NOT_EXPANDABLE , dataset , type , segments , fieldSegments , objectSchema ) ; e . initCause ( cause ) ; throw e ; } fieldSegments . addAll ( expandedFieldSegments . segments ) ; break ; } else { throw new FieldPathException ( FieldPathException . ErrorKind . NOT_EXPANDABLE , dataset , type , segments , fieldSegments , objectSchema ) ; } } else { throw new FieldPathException ( FieldPathException . ErrorKind . NOT_EXPANDABLE , dataset , type , segments , fieldSegments , schema ) ; } } } else if ( requireFullPath && segmentType != null ) { throw new FieldPathException ( FieldPathException . ErrorKind . NOT_FULL , dataset , type , segments , fieldSegments ) ; } return new FieldPath <> ( type , fieldSegments , ! autoExpand ) ; }
Creates a field path given a data set and the field path in symbolic form.

@param dataset the data set
@param type the type name from which to bind the field path
@param path the symbolic field path
@param autoExpand {@code true} if the field path should be expanded (if needed) to a full path referencing
an object field whose type is a non-reference type, otherwise the field path is not expanded
@param requireFullPath {@code true} if a full path is required when {@code autoExpand} is {@code false}.
Ignored if {@code autoExpand} is {@code true}.
@param traverseSequences {@code true} if lists, sets and maps are traversed, otherwise an
{@code IllegalArgumentException} will be thrown
@return the field path
@throws IllegalArgumentException if the symbolic field path is ill-formed and cannot be bound
Creates a field path given a data set and the field path in symbolic form .