001/*
002 * Copyright 2012-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 *      http://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.boot.origin;
018
019import org.springframework.util.ObjectUtils;
020
021/**
022 * A wrapper for an {@link Object} value and {@link Origin}.
023 *
024 * @author Madhura Bhave
025 * @author Phillip Webb
026 * @since 2.0.0
027 * @see #of(Object)
028 * @see #of(Object, Origin)
029 */
030public class OriginTrackedValue implements OriginProvider {
031
032        private final Object value;
033
034        private final Origin origin;
035
036        private OriginTrackedValue(Object value, Origin origin) {
037                this.value = value;
038                this.origin = origin;
039        }
040
041        /**
042         * Return the tracked value.
043         * @return the tracked value
044         */
045        public Object getValue() {
046                return this.value;
047        }
048
049        @Override
050        public Origin getOrigin() {
051                return this.origin;
052        }
053
054        @Override
055        public boolean equals(Object obj) {
056                if (obj == null || obj.getClass() != getClass()) {
057                        return false;
058                }
059                return ObjectUtils.nullSafeEquals(this.value, ((OriginTrackedValue) obj).value);
060        }
061
062        @Override
063        public int hashCode() {
064                return ObjectUtils.nullSafeHashCode(this.value);
065        }
066
067        @Override
068        public String toString() {
069                return (this.value != null) ? this.value.toString() : null;
070        }
071
072        public static OriginTrackedValue of(Object value) {
073                return of(value, null);
074        }
075
076        /**
077         * Create an {@link OriginTrackedValue} containing the specified {@code value} and
078         * {@code origin}. If the source value implements {@link CharSequence} then so will
079         * the resulting {@link OriginTrackedValue}.
080         * @param value the source value
081         * @param origin the origin
082         * @return an {@link OriginTrackedValue} or {@code null} if the source value was
083         * {@code null}.
084         */
085        public static OriginTrackedValue of(Object value, Origin origin) {
086                if (value == null) {
087                        return null;
088                }
089                if (value instanceof CharSequence) {
090                        return new OriginTrackedCharSequence((CharSequence) value, origin);
091                }
092                return new OriginTrackedValue(value, origin);
093        }
094
095        /**
096         * {@link OriginTrackedValue} for a {@link CharSequence}.
097         */
098        private static class OriginTrackedCharSequence extends OriginTrackedValue
099                        implements CharSequence {
100
101                OriginTrackedCharSequence(CharSequence value, Origin origin) {
102                        super(value, origin);
103                }
104
105                @Override
106                public int length() {
107                        return getValue().length();
108                }
109
110                @Override
111                public char charAt(int index) {
112                        return getValue().charAt(index);
113                }
114
115                @Override
116                public CharSequence subSequence(int start, int end) {
117                        return getValue().subSequence(start, end);
118                }
119
120                @Override
121                public CharSequence getValue() {
122                        return (CharSequence) super.getValue();
123                }
124
125        }
126
127}