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. The name of the author may not be used to endorse or promote products derived from this software without
 *       specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

import de.unkrig.commons.lang.AssertionUtil;
import de.unkrig.commons.nullanalysis.NotNull;

/**
 * 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  Transformer
    identity() {
        return TransformerUtil.IDENTITY;
    }

    @SuppressWarnings("rawtypes") private static final Transformer IDENTITY = new Transformer() {

        @Override public Object
        transform(Object in) { return in; }
    };

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

* 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 Transformer source) { return new TransformerWhichThrows() { @Override @NotNull public O transform(I in) { return source.transform(in); } }; } /** * 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 @NotNull public O transform(I in) { return source.transform(in); } }; } /** * @return A {@link Transformer} which calls the {@code delegate}, except when the {@code subject} equals the * {@code extraInput}, when it returns {@code extraOutput} */ public static Transformer combine(final I extraInput, final O extraOutput, final Transformer delegate) { return new Transformer() { @Override @NotNull public O transform(I in) { if (in.equals(extraInput)) return extraOutput; return delegate.transform(in); } }; } /** * @return A {@link TransformerWhichThrows} which calls the {@code delegate}, except when the {@code subject} * equals the {@code extraInput}, when it returns {@code extraOutput} */ public static TransformerWhichThrows combine(final I extraInput, final O extraOutput, final TransformerWhichThrows delegate) { return new TransformerWhichThrows() { @Override @NotNull public O transform(I in) throws EX { if (in.equals(extraInput)) return extraOutput; 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 addMappings(final Transformer transformer, 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 Transformer() { @Override @NotNull public O transform(I in) { O out = m.get(in); if (out != null) return out; return transformer.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 @NotNull 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. */ public static Transformer cache(final Transformer delegate) { return new Transformer() { final WeakHashMap cache = new WeakHashMap(); @Override @NotNull public O transform(I in) { O out = this.cache.get(in); if (out != null) return out; out = delegate.transform(in); this.cache.put(in, out); return out; } }; } }