blob: 5e79466b11fff35ede99545c01c581bdd7a6543c [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License 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.datatorrent.lib.appdata.schemas;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
/**
* This enum is used to represent data types throughout AppData Framework.
* @since 3.0.0
*/
public enum Type implements Serializable
{
/**
* Boolean data type.
*/
BOOLEAN("boolean", 1, JSONType.BOOLEAN, Boolean.class,
Collections.unmodifiableSet(new HashSet<Type>())),
/**
* String data type.
*/
STRING("string", -1, JSONType.STRING, String.class,
Collections.unmodifiableSet(new HashSet<Type>())),
/**
* Char data type.
*/
CHAR("char", 2, JSONType.STRING, Character.class,
ImmutableSet.of(STRING)),
/**
* Double data type.
*/
DOUBLE("double", 8, JSONType.NUMBER, Double.class,
Collections.unmodifiableSet(new HashSet<Type>())),
/**
* Float data type.
*/
FLOAT("float", 4, JSONType.NUMBER, Float.class,
ImmutableSet.of(DOUBLE)),
/**
* Long data type.
*/
LONG("long", 8, JSONType.NUMBER, Long.class,
Collections.unmodifiableSet(new HashSet<Type>())),
/**
* Integer data type.
*/
INTEGER("integer", 4, JSONType.NUMBER, Integer.class,
ImmutableSet.of(LONG)),
/**
* Short data type.
*/
SHORT("short", 2, JSONType.NUMBER, Short.class,
ImmutableSet.of(INTEGER, LONG)),
/**
* Byte data type.
*/
BYTE("byte", 1, JSONType.NUMBER, Byte.class,
ImmutableSet.of(SHORT, INTEGER, LONG)),
/**
* Object data type.
*/
OBJECT("object", -1, JSONType.INVALID, Object.class,
Collections.unmodifiableSet(new HashSet<Type>()));
/**
* A set containing all the numeric types.
*/
public static final Set<Type> NUMERIC_TYPES = ImmutableSet.of(BYTE, SHORT, INTEGER, LONG, FLOAT, DOUBLE);
/**
* A set containing all the non numeric types.
*/
public static final Set<Type> NON_NUMERIC_TYPES = ImmutableSet.of(BOOLEAN, CHAR, STRING);
/**
* A map from the names to the types.
*/
public static final Map<String, Type> NAME_TO_TYPE;
/**
* A map from a class representing the type to the type itself.
*/
public static final Map<Class<?>, Type> CLASS_TO_TYPE;
static {
Map<String, Type> nameToType = Maps.newHashMap();
for (Type type : Type.values()) {
nameToType.put(type.getName(), type);
}
NAME_TO_TYPE = Collections.unmodifiableMap(nameToType);
Map<Class<?>, Type> clazzToType = Maps.newHashMap();
for (Type type : Type.values()) {
clazzToType.put(type.getClazz(), type);
}
CLASS_TO_TYPE = Collections.unmodifiableMap(clazzToType);
}
/**
* The name of the type.
*/
private final String name;
/**
* The type of the corresponding JSON element.
*/
private final JSONType jsonType;
/**
* Class of the corresponding Java type.
*/
private final Class<?> clazz;
/**
* In the case of numeric types, there may be a "higher" type. For example
* ints can be promoted to longs. This set holds all of the types that this
* type could be promoted to. If this type cannot be promoted then this will be empty.
*/
private final Set<Type> higherTypes;
/**
* The number of bytes required to store a value of this type. If a value of
* this type can be of variable length then this would be -1.
*/
private final int byteSize;
/**
* Creates a type enum.
* @param name The name of the type.
* @param byteSize The number of bytes a value of this type would occupy. -1 if variable length.
* @param jsonType The type of corresponding json values.
* @param clazz The Class of the corresponding Java type.
* @param higherTypes The set of types to which this type can be promoted.
*/
Type(String name, int byteSize, JSONType jsonType, Class<?> clazz, Set<Type> higherTypes)
{
this.name = name;
this.byteSize = byteSize;
this.jsonType = jsonType;
this.clazz = clazz;
this.higherTypes = higherTypes;
}
/**
* Gets the name of the type.
* @return The name of the type.
*/
public String getName()
{
return name;
}
/**
* Gets the byte size of the value.
* @return The byte size of the value.
*/
public int getByteSize()
{
return byteSize;
}
/**
* Gets the corresponding JSONType of this type.
* @return The corresponding JSONType of this type.
*/
public JSONType getJSONType()
{
return jsonType;
}
/**
* Gets the Java class corresponding to this type.
* @return The Java class corresponding to this type.
*/
public Class<?> getClazz()
{
return clazz;
}
/**
* Gets the set of types to which this type can be promoted.
* @return The set of types to which this type can be promoted.
*/
public Set<Type> getHigherTypes()
{
return higherTypes;
}
/**
* Determines if the given type is a higher type of this type.
* @param type The type which may or not be a parent of this type.
* @return True if the given type is a higher type of this type. False otherwise.
*/
public boolean isChildOf(Type type)
{
return higherTypes.contains(type);
}
/**
* Determines if one of the given types is a child of the other.
* @param a This type will be checked to see if it is a child of b.
* @param b This type will be checked to see if it is a child of a.
* @return True if one of the given types is a child of the other. False otherwise.
*/
public static boolean areRelated(Type a, Type b)
{
return a == b || a.isChildOf(b) || b.isChildOf(a);
}
/**
* Gets the type corresponding to the given name.
* @param name The name of the type.
* @return The type corresponding to the name or null if there is no type
* corresponding to the given name.
*/
public static Type getType(String name)
{
return NAME_TO_TYPE.get(name);
}
public static Type getTypeEx(String name)
{
Type type = getType(name);
Preconditions.checkArgument(type != null, name + " is not a valid type.");
return type;
}
/**
* Promotes the given object from the "from" type to the "to" type.
* @param from The current type of the given object.
* @param to The desired type for the given object.
* @param o The object whose type must be converted.
* @return The result of promoting the given object o to the "to" type.
*/
public static Object promote(Type from, Type to, Object o)
{
if (from == to) {
return o;
}
Preconditions.checkArgument(!(from == Type.BOOLEAN || from == Type.CHAR || from == Type.LONG
|| from == Type.DOUBLE), "Cannot convert " + Type.BOOLEAN.getName() + ", " + Type.CHAR.getName()
+ ", " + Type.LONG.getName() + ", or " + Type.DOUBLE + " to a larger type.");
Preconditions.checkArgument(from.getHigherTypes().contains(to),
from.getName() + " cannot be promoted to " + to.getName());
if (from == Type.FLOAT && to == Type.DOUBLE) {
return (Double)((Float)o).doubleValue();
}
if (from == Type.BYTE) {
if (to == Type.SHORT) {
return (Short)((Byte)o).shortValue();
} else if (to == Type.INTEGER) {
return (Integer)((Byte)o).intValue();
} else if (to == Type.LONG) {
return (Long)((Byte)o).longValue();
}
}
if (from == Type.SHORT) {
if (to == Type.INTEGER) {
return (Integer)((Short)o).intValue();
} else if (to == Type.LONG) {
return (Long)((Short)o).longValue();
}
}
if (from == Type.INTEGER
&& to == Type.LONG) {
return (Long)((Integer)o).longValue();
}
throw new UnsupportedOperationException("This should not happen.");
}
}