Facets.java

/*
 * Copyright 2007-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package com.amazon.ion.facet;

/**
 * Utility methods for working with facets.
 *
 * @see Faceted
 *
 */
public class Facets
{
    //   *** IMPLEMENTATION NOTE ***
    //
    // In order to ensure fast operation, the code here is denormalized.
    // It's very simple so I find that preferable to additional null-checks
    // that would be required by following the "Once And Only Once" rule.


    /**
     * Returns a facet of the given subject if supported, returning null
     * otherwise.
     * <p>
     * This does not attempt to cast the subject to the requested type, since
     * the {@link Faceted} interface declares the intent to control the
     * conversion.
     *
     * @return the requested facet, or null if {@code subject} is null or if
     *  subject doesn't support the requested facet type.
     */
    public static <T> T asFacet(Class<T> facetType, Faceted subject)
    {
        return subject == null ? null : subject.asFacet(facetType);
    }


    /**
     * Returns a facet of the given subject if supported, returning null
     * otherwise.
     * <p>
     * If the subject implements {@link Faceted}, then this conversion is
     * delegated to {@link Faceted#asFacet(Class)}. Otherwise, a simple
     * cast of the subject is attempted.
     *
     * @return the requested facet, or null if {@code subject} is null or if
     *  subject doesn't support the requested facet type.
     */
    public static <T> T asFacet(Class<T> facetType, Object subject)
    {
        T facet = null;
        if (subject instanceof Faceted)
        {
            facet = ((Faceted)subject).asFacet(facetType);
        }
        else if (facetType.isInstance(subject))
        {
            facet = facetType.cast(subject);
        }

        return facet;
    }


    /**
     * Returns a facet of the given subject if supported, throwing an
     * exception otherwise.
     * <p>
     * This does not attempt to cast the subject to the requested type, since
     * the {@link Faceted} interface declares the intent to control the
     * conversion.
     *
     * @return not null.
     *
     * @throws UnsupportedFacetException if {@code subject} is null or if the
     *  subject doesn't support the requested facet type.
     */
    public static <T> T assumeFacet(Class<T> facetType, Faceted subject)
    {
        if (subject != null)
        {
            T facet = subject.asFacet(facetType);
            if (facet != null) return facet;
        }

        throw new UnsupportedFacetException(facetType, subject);
    }


    /**
     * Returns a facet of the given subject if supported, throwing an
     * exception otherwise.
     * <p>
     * If the subject implements {@link Faceted}, then this conversion is
     * delegated to {@link Faceted#asFacet(Class)}. Otherwise, a simple
     * cast of the subject is attempted.
     *
     * @return not null.
     *
     * @throws UnsupportedFacetException if {@code subject} is null or if the
     *  subject doesn't support the requested facet type.
     */
    public static <T> T assumeFacet(Class<T> facetType, Object subject)
    {
        if (subject instanceof Faceted)
        {
            T facet = ((Faceted)subject).asFacet(facetType);
            if (facet != null) return facet;
        }
        else if (facetType.isInstance(subject))
        {
            return facetType.cast(subject);
        }

        throw new UnsupportedFacetException(facetType, subject);
    }
}