All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.unkrig.commons.lang.protocol.TransformerUtil Maven / Gradle / Ivy


/*
 * de.unkrig.commons - A general-purpose Java class library
 *
 * Copyright (c) 2011, Arno Unkrig
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *       following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 *       following disclaimer in the documentation and/or other materials provided with the distribution.
 *    3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
 *       products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package de.unkrig.commons.lang.protocol;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.WeakHashMap;

import de.unkrig.commons.lang.AssertionUtil;

/**
 * Various {@link Transformer}-related utility methods.
 */
public final
class TransformerUtil {

    static { AssertionUtil.enableAssertionsForThisClass(); }

    private
    TransformerUtil() {}

    /**
     * @return A {@link Transformer} that transforms any object reference to itself.
     */
    @SuppressWarnings("unchecked") public static  TransformerWhichThrows
    identity() { return TransformerUtil.IDENTITY; }

    @SuppressWarnings("rawtypes") private static final Transformer
    IDENTITY = new Transformer() { @Override public Object transform(Object in) { return in; } };

    /**
     * @return A transformer that feeds subjects through a chain of delegate transformers
     */
    public static  TransformerWhichThrows
    chain(final TransformerWhichThrows... transformers) {

        if (transformers.length == 0) return TransformerUtil.identity();

        if (transformers.length == 1) return transformers[0];

        return new TransformerWhichThrows() {

            @Override public T
            transform(T in) throws EX {
                for (TransformerWhichThrows transformer : transformers) {
                    in = transformer.transform(in);
                }
                return in;
            }
        };
    }

    /**
     * Converts a {@link TransformerWhichThrows}{@code } into a {@link
     * TransformerWhichThrows}{@code }.
     * 

* That is possible iff: *

*
    *
  • The target's input type is a subclass of the source's input type, and *
  • The source's output type is a subclass of the target's output type. *
* * @param The transformers' input type * @param The transformers' output type * @param The target transformer's exception */ public static TransformerWhichThrows asTransformerWhichThrows(final TransformerWhichThrows source) { @SuppressWarnings("unchecked") TransformerWhichThrows result = (TransformerWhichThrows) source; return result; } /** * Converts a {@link TransformerWhichThrows} into a {@link Transformer}. *

* That is possible iff: *

*
    *
  • The target's input type is a subclass of the source's input type, and *
  • The source's output type is a subclass of the target's output type *
  • The source's exception is a subclass of {@link RuntimeException}. *
* * @param The transformers' input type * @param The transformers' output type * @param The source transformer's exception */ public static Transformer asTransformer(final TransformerWhichThrows source) { return new Transformer() { @Override public O transform(I in) { return source.transform(in); } }; } /** * @return A {@link TransformerWhichThrows} which calls the delegate, except when the subject * equals the extraInput, when it returns extraOutput */ public static TransformerWhichThrows combine( final I extraInput, final O extraOutput, final TransformerWhichThrows delegate ) { return new TransformerWhichThrows() { @Override public O transform(I in) throws EX { if (in.equals(extraInput)) return extraOutput; return delegate.transform(in); } }; } /** * @return A {@link TransformerWhichThrows} in which the given keys and values override the mappings of the * delegate */ @SuppressWarnings("unchecked") public static TransformerWhichThrows addMappings( final TransformerWhichThrows delegate, Object... keysAndValues ) { final Map m = new HashMap(); for (int i = 0; i < keysAndValues.length;) { I key = (I) keysAndValues[i++]; assert key != null; O value = (O) keysAndValues[i++]; assert value != null; m.put(key, value); } return new TransformerWhichThrows() { @Override public O transform(I in) throws EX { O out = m.get(in); if (out != null) return out; return delegate.transform(in); } }; } /** * @return A {@link Transformer} in which the given keys and values override the mappings of the delegate. */ @SuppressWarnings("unchecked") public static Transformer fromMappings(Object... keysAndValues) { final Map m = new HashMap(); for (int i = 0; i < keysAndValues.length;) { m.put((I) keysAndValues[i++], (O) keysAndValues[i++]); } return new Transformer() { @Override public O transform(I in) { return m.get(in); } }; } /** * A transformer which lets a delegate transform the inputs, but at most once for each non-equal * input. *

* This method is not thread-safe. To get a thread-safe cache, use {@link #cache(TransformerWhichThrows, Map)}. *

*/ public static TransformerWhichThrows cache(final TransformerWhichThrows delegate) { return TransformerUtil.cache(delegate, new WeakHashMap()); } /** * A transformer which lets a delegate transform the inputs, and remembers the result in the * cache map. *

* This method is not thread-safe. To make it thread-safe, pass a {@link Collections#synchronizedMap(Map)} as * the cache argument. *

* * @param cache Typically a {@link HashMap}, or a {@link TreeMap#TreeMap(java.util.Comparator)}, or a * {@link WeakHashMap}, or a {@link Collections#synchronizedMap(Map)} (for thread-safety) */ public static TransformerWhichThrows cache(final TransformerWhichThrows delegate, final Map cache) { return new TransformerWhichThrows() { @Override public O transform(I in) throws EX { O out = cache.get(in); if (out != null) return out; out = delegate.transform(in); cache.put(in, out); return out; } }; } /** * Wraps the delegate such that its declared exception is caught, ignored, and the * defaultValue is returned. */ public static Transformer ignoreExceptions( final Class exceptionClass, final TransformerWhichThrows delegate, final O defaultValue ) { return new Transformer() { @Override public O transform(I in) { try { return delegate.transform(in); } catch (RuntimeException re) { if (!exceptionClass.isAssignableFrom(re.getClass())) throw re; } catch (Error e) { // SUPPRESS CHECKSTYLE IllegalCatch if (!exceptionClass.isAssignableFrom(e.getClass())) throw e; } catch (Throwable t) { // SUPPRESS CHECKSTYLE IllegalCatch assert exceptionClass.isAssignableFrom(t.getClass()); } return defaultValue; } }; } }