/* * Copyright (C) 2009 Google Inc. * * Licensed 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.smartandroid.sa.json; import java.lang.reflect.Type; /** * A holder class for an object and its type * * @author Inderjeet Singh */ final class ObjectTypePair { private Object obj; final Type type; private final boolean preserveType; private final boolean systemOnly; ObjectTypePair(Object obj, Type type, boolean preserveType, boolean systemOnly) { this.obj = obj; this.type = type; this.preserveType = preserveType; this.systemOnly = systemOnly; } Object getObject() { return obj; } void setObject(Object obj) { this.obj = obj; } Type getType() { return type; } @Override public String toString() { return String.format("preserveType: %b, type: %s, obj: %s", preserveType, type, obj); } <HANDLER> Pair<HANDLER, ObjectTypePair> getMatchingHandler( ParameterizedTypeHandlerMap<HANDLER> handlers) { HANDLER handler = null; if (!preserveType && obj != null) { // First try looking up the handler for the actual type ObjectTypePair moreSpecificType = toMoreSpecificType(); handler = handlers.getHandlerFor(moreSpecificType.type, systemOnly); if (handler != null) { return new Pair<HANDLER, ObjectTypePair>(handler, moreSpecificType); } } // Try the specified type handler = handlers.getHandlerFor(type, systemOnly); return handler == null ? null : new Pair<HANDLER, ObjectTypePair>( handler, this); } ObjectTypePair toMoreSpecificType() { if (preserveType || obj == null) { return this; } Type actualType = getActualTypeIfMoreSpecific(type, obj.getClass()); if (actualType == type) { return this; } return new ObjectTypePair(obj, actualType, true, systemOnly); } Type getMoreSpecificType() { if (preserveType || obj == null) { return type; } return getActualTypeIfMoreSpecific(type, obj.getClass()); } // This takes care of situations where the field was declared as an Object, // but the // actual value contains something more specific. See Issue 54. // TODO (inder): This solution will not work if the field is of a generic // type, but // the actual object is of a raw type (which is a sub-class of the generic // type). static Type getActualTypeIfMoreSpecific(Type type, Class<?> actualClass) { if (type instanceof Class<?>) { Class<?> typeAsClass = (Class<?>) type; if (typeAsClass.isAssignableFrom(actualClass)) { type = actualClass; } if (type == Object.class) { type = actualClass; } } return type; } @Override public int hashCode() { // Not using type.hashCode() since I am not sure if the subclasses of // type reimplement // hashCode() to be equal for equal types return ((obj == null) ? 31 : obj.hashCode()); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } ObjectTypePair other = (ObjectTypePair) obj; if (this.obj == null) { if (other.obj != null) { return false; } } else if (this.obj != other.obj) { // Checking for reference equality return false; } if (type == null) { if (other.type != null) { return false; } } else if (!type.equals(other.type)) { return false; } return preserveType == other.preserveType && systemOnly == other.systemOnly; } public boolean isPreserveType() { return preserveType; } public boolean isSystemOnly() { return systemOnly; } }