001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.expression;
018
019import org.springframework.core.convert.TypeDescriptor;
020import org.springframework.lang.Nullable;
021import org.springframework.util.ObjectUtils;
022
023/**
024 * Encapsulates an object and a {@link TypeDescriptor} that describes it.
025 * The type descriptor can contain generic declarations that would not
026 * be accessible through a simple {@code getClass()} call on the object.
027 *
028 * @author Andy Clement
029 * @author Juergen Hoeller
030 * @since 3.0
031 */
032public class TypedValue {
033
034        /**
035         * {@link TypedValue} for {@code null}.
036         */
037        public static final TypedValue NULL = new TypedValue(null);
038
039
040        @Nullable
041        private final Object value;
042
043        @Nullable
044        private TypeDescriptor typeDescriptor;
045
046
047        /**
048         * Create a {@link TypedValue} for a simple object. The {@link TypeDescriptor}
049         * is inferred from the object, so no generic declarations are preserved.
050         * @param value the object value
051         */
052        public TypedValue(@Nullable Object value) {
053                this.value = value;
054                this.typeDescriptor = null;  // initialized when/if requested
055        }
056
057        /**
058         * Create a {@link TypedValue} for a particular value with a particular
059         * {@link TypeDescriptor} which may contain additional generic declarations.
060         * @param value the object value
061         * @param typeDescriptor a type descriptor describing the type of the value
062         */
063        public TypedValue(@Nullable Object value, @Nullable TypeDescriptor typeDescriptor) {
064                this.value = value;
065                this.typeDescriptor = typeDescriptor;
066        }
067
068
069        @Nullable
070        public Object getValue() {
071                return this.value;
072        }
073
074        @Nullable
075        public TypeDescriptor getTypeDescriptor() {
076                if (this.typeDescriptor == null && this.value != null) {
077                        this.typeDescriptor = TypeDescriptor.forObject(this.value);
078                }
079                return this.typeDescriptor;
080        }
081
082
083        @Override
084        public boolean equals(@Nullable Object other) {
085                if (this == other) {
086                        return true;
087                }
088                if (!(other instanceof TypedValue)) {
089                        return false;
090                }
091                TypedValue otherTv = (TypedValue) other;
092                // Avoid TypeDescriptor initialization if not necessary
093                return (ObjectUtils.nullSafeEquals(this.value, otherTv.value) &&
094                                ((this.typeDescriptor == null && otherTv.typeDescriptor == null) ||
095                                                ObjectUtils.nullSafeEquals(getTypeDescriptor(), otherTv.getTypeDescriptor())));
096        }
097
098        @Override
099        public int hashCode() {
100                return ObjectUtils.nullSafeHashCode(this.value);
101        }
102
103        @Override
104        public String toString() {
105                return "TypedValue: '" + this.value + "' of [" + getTypeDescriptor() + "]";
106        }
107
108}