/*******************************************************************************
* Copyright (c) 2015, 2016 itemis AG and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Alexander Nyßen (itemis AG) - initial API and implementation
*
*******************************************************************************/
package org.eclipse.gef.common.reflect;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Base64;
import com.google.common.reflect.TypeToken;
/**
* Utilities around {@link TypeToken}
*
* @author anyssen
*
*/
public class Types {
private static Method isTypeTokenAssignableMethod;
/**
* Deserializes the given {@link String}-representation in Base64 encoding
* into a {@link TypeToken}.
*
* @param string
* The {@link String}-representation to deserialize.
* @return The deserialized {@link TypeToken}.
*/
public static final TypeToken<?> deserialize(String string) {
try {
ByteArrayInputStream bis = new ByteArrayInputStream(
Base64.getDecoder().decode(string));
ObjectInputStream ois = new ObjectInputStream(bis);
TypeToken<?> typeToken;
typeToken = (TypeToken<?>) ois.readObject();
ois.close();
return typeToken;
} catch (ClassNotFoundException | ClassCastException e) {
throw new IllegalArgumentException(
"String does not seem to be of type TokeToken.");
} catch (IOException e2) {
throw new IllegalArgumentException(
"Could not deserialize TypeToken.");
}
}
/**
* Returns whether the given 'candidate' superType is a super type of the
* given 'candidate' subtype.
*
* This is replacement for TypeToken.isAssignableFrom(TypeToken), which has
* been deprecated and replaced by TypeToken.isSuperTypeOf(TypeToken) in
* Google Guava 19.0.0. As we want to support various Google Guava versions
* from 15.0.0 onwards, this methods delegates to the appropriate
* implementation using reflection.
*
* @param superType
* The 'candidate' superType.
* @param subType
* The 'candidate' subType.
* @return <code>true</code> when the given 'candidate' superType is indeed
* a super type of the given 'candidate' subType, <code>false</code>
* otherwise.
*/
public static final boolean isAssignable(TypeToken<?> superType,
TypeToken<?> subType) {
// TypeToken.isAssignableFrom(TypeToken) has been deprecated in Guava
// 19, where TypeToken.isSuperTypeOf(TypeToken) has been introduced as a
// workaround. As we want to support a broad range of Guava versions, we
// have use reflection here to access the respective functionality.
// XXX: Replace this with direct calls to
// TypeToken.isSuperTypeOf(TypeToken) when removing support for Guava <
// 19.
if (isTypeTokenAssignableMethod == null) {
try {
isTypeTokenAssignableMethod = TypeToken.class
.getDeclaredMethod("isSupertypeOf", TypeToken.class);
} catch (NoSuchMethodException e) {
// e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
if (isTypeTokenAssignableMethod == null) {
try {
isTypeTokenAssignableMethod = TypeToken.class
.getDeclaredMethod("isAssignableFrom",
TypeToken.class);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException(
"Neither TypeToken.isAssignableFrom(TypeToken), nor TypeToken.isSuperTypeOf(TypeToken) seems to be supported by the given Guava version.");
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
try {
return (boolean) isTypeTokenAssignableMethod.invoke(superType,
subType);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Serializes a given {@link TypeToken} into a {@link String}
* representation.
*
* @param typeToken
* The {@link TypeToken} to serialize.
* @return The string representation of the {@link TypeToken} encoded in
* Base64.
*/
public static final String serialize(TypeToken<?> typeToken) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos);
os.writeObject(typeToken);
os.close();
return Base64.getEncoder().encodeToString(bos.toByteArray());
} catch (IOException e) {
throw new IllegalArgumentException(
"Could not serialize " + typeToken);
}
}
}