/** * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * Copyright (C) 2017 Dan Mulloy * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program; * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ package com.comphenix.protocol.wrappers; import java.lang.reflect.Array; import java.util.Optional; import java.util.function.Function; import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.utility.MinecraftReflection; /** * Utility class for converters * @author dmulloy2 */ @SuppressWarnings("unchecked") public class Converters { /** * Returns a converter that ignores null elements, so that the underlying converter doesn't have to worry about them. * @param converter Underlying converter * @param Element type * @return An ignore null converter */ public static EquivalentConverter ignoreNull(final EquivalentConverter converter) { return new EquivalentConverter() { @Override public T getSpecific(Object generic) { return generic != null ? converter.getSpecific(generic) : null; } @Override public Object getGeneric(T specific) { return specific != null ? converter.getGeneric(specific) : null; } @Override public Class getSpecificType() { return converter.getSpecificType(); } }; } /** * Returns a converter that passes generic and specific values through without converting. * @param clazz Element class * @param Element type * @return A passthrough converter */ public static EquivalentConverter passthrough(final Class clazz) { return ignoreNull(new EquivalentConverter() { @Override public T getSpecific(Object generic) { return (T) generic; } @Override public Object getGeneric(T specific) { return specific; } @Override public Class getSpecificType() { return clazz; } }); } /** * Creates a simple converter for wrappers with {@code getHandle()} and {@code fromHandle(...)} methods. With Java 8, * converters can be reduced to a single line (see {@link BukkitConverters#getWrappedGameProfileConverter()}). * @param toHandle Function from wrapper to handle (i.e. {@code getHandle()}) * @param fromHandle Function from handle to wrapper (i.e. {@code fromHandle(Object)}) * @param Wrapper type * @return A handle converter */ public static EquivalentConverter handle(final Function toHandle, final Function fromHandle, final Class specificType) { return new EquivalentConverter() { @Override public T getSpecific(Object generic) { return fromHandle.apply(generic); } @Override public Object getGeneric(T specific) { return toHandle.apply(specific); } @Override public Class getSpecificType() { return specificType; } }; } /** * Creates a generic array converter. Converts a NMS object array to and from a wrapper array by converting * each element individually. * * @param nmsClass NMS class * @param converter Underlying converter * @param Generic type * @return An array converter */ public static EquivalentConverter array(final Class nmsClass, final EquivalentConverter converter) { return new EquivalentConverter() { @Override public T[] getSpecific(Object generic) { Object[] array = (Object[]) generic; Class clazz = getSpecificType(); T[] result = clazz.cast(Array.newInstance(clazz.getComponentType(), array.length)); // Unwrap every item for (int i = 0; i < result.length; i++) { result[i] = converter.getSpecific(array[i]); } return result; } @Override public Object getGeneric(T[] specific) { Object[] result = (Object[]) Array.newInstance(nmsClass, specific.length); // Wrap every item for (int i = 0; i < result.length; i++) { result[i] = converter.getGeneric(specific[i]); } return result; } @Override public Class getSpecificType() { return (Class) MinecraftReflection.getArrayClass(converter.getSpecificType()); } }; } public static EquivalentConverter> optional(final EquivalentConverter converter) { return new EquivalentConverter>() { @Override public Object getGeneric(Optional specific) { return specific.map(converter::getGeneric); } @Override public Optional getSpecific(Object generic) { Optional optional = (Optional) generic; return optional.map(converter::getSpecific); } @Override public Class> getSpecificType() { return (Class>) Optional.empty().getClass(); } }; } }