class DefaultReferenceEntityReferenceResolver implements EntityReferenceResolver<EntityReference> {

    public EntityReference resolve(EntityReference referenceToResolve, EntityType type)
    {
        EntityReference normalizedReference;

        // If the passed type is a supertype of the reference to resolve's type then we need to insert a top level
        // reference.
        if (type.ordinal() > referenceToResolve.getType().ordinal()) {
            normalizedReference = new EntityReference(getDefaultValue(type), type, referenceToResolve.clone());
        } else {
            normalizedReference = referenceToResolve.clone();
        }

        // Check all references and parent references which have a NULL name and replace them with default values.
        // In addition insert references where needed.
        EntityReference reference = normalizedReference;
        while (reference != null) {
            List<EntityType> types = this.nextAllowedEntityTypes.get(reference.getType());
            if (reference.getParent() != null && !types.isEmpty() && !types.contains(reference.getParent().getType())) {
                // The parent reference isn't the allowed parent: insert an allowed reference
                EntityReference newReference = new EntityReference(
                    getDefaultValue(types.get(0)), types.get(0), reference.getParent());
                reference.setParent(newReference);
            } else if (reference.getParent() == null && !types.isEmpty()) {
                // The top reference isn't the allowed top level reference, add a parent reference
                EntityReference newReference = new EntityReference(
                    getDefaultValue(types.get(0)), types.get(0));
                reference.setParent(newReference);
            } else if (reference.getParent() != null && types.isEmpty()) {
                // There's a parent but not of the correct type... it means the reference is invalid
                throw new InvalidEntityReferenceException("Invalid reference [" + referenceToResolve + "]");
            }
            reference = reference.getParent();
        }

        // If the passed type is a subtype of the reference to resolve's type then we extract the reference.
        if (type.ordinal() < referenceToResolve.getType().ordinal()) {
            normalizedReference = normalizedReference.extractReference(type);
        }

        return normalizedReference;
    }

}