001/*
002 * Copyright 2022-2025 Revetware LLC.
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 com.soklet.converter;
018
019import javax.annotation.Nonnull;
020import javax.annotation.Nullable;
021import javax.annotation.concurrent.NotThreadSafe;
022import java.lang.reflect.Type;
023import java.util.Optional;
024
025import static java.util.Objects.requireNonNull;
026
027/**
028 * Thrown if an error occurs during value conversion.
029 * <p>
030 * For example, a {@link ValueConverter} for 'from' type {@link String} and 'to' type {@link Integer}
031 * might throw this exception if the 'from' value is {@code "abc"}.
032 *
033 * @author <a href="https://www.revetkn.com">Mark Allen</a>
034 */
035@NotThreadSafe
036public class ValueConversionException extends Exception {
037        @Nonnull
038        private final Type fromType;
039        @Nullable
040        private final Object fromValue;
041        @Nonnull
042        private final Type toType;
043
044        /**
045         * Creates an exception that describes the value conversion error.
046         *
047         * @param message   a message describing the error
048         * @param fromType  the 'from' type
049         * @param fromValue the value supplied for the 'from' type
050         * @param toType    the 'to' type
051         */
052        public ValueConversionException(@Nullable String message,
053                                                                                                                                        @Nonnull Type fromType,
054                                                                                                                                        @Nullable Object fromValue,
055                                                                                                                                        @Nonnull Type toType) {
056                super(message);
057
058                requireNonNull(fromType);
059                requireNonNull(toType);
060
061                this.fromType = fromType;
062                this.fromValue = fromValue;
063                this.toType = toType;
064        }
065
066        /**
067         * Creates an exception that describes the value conversion error.
068         *
069         * @param cause     the underlying exception that caused this one to be thrown
070         * @param fromType  the 'from' type
071         * @param fromValue the value supplied for the 'from' type
072         * @param toType    the 'to' type
073         */
074        public ValueConversionException(@Nullable Throwable cause,
075                                                                                                                                        @Nonnull Type fromType,
076                                                                                                                                        @Nullable Object fromValue,
077                                                                                                                                        @Nonnull Type toType) {
078                super(cause);
079
080                requireNonNull(fromType);
081                requireNonNull(toType);
082
083                this.fromType = fromType;
084                this.fromValue = fromValue;
085                this.toType = toType;
086        }
087
088        /**
089         * Creates an exception that describes the value conversion error.
090         *
091         * @param message   a message describing the error
092         * @param cause     the underlying exception that caused this one to be thrown
093         * @param fromType  the 'from' type
094         * @param fromValue the value supplied for the 'from' type
095         * @param toType    the 'to' type
096         */
097        public ValueConversionException(@Nullable String message,
098                                                                                                                                        @Nullable Throwable cause,
099                                                                                                                                        @Nonnull Type fromType,
100                                                                                                                                        @Nullable Object fromValue,
101                                                                                                                                        @Nonnull Type toType) {
102                super(message, cause);
103
104                requireNonNull(fromType);
105                requireNonNull(toType);
106
107                this.fromType = fromType;
108                this.fromValue = fromValue;
109                this.toType = toType;
110        }
111
112        /**
113         * The 'from' type of the failed {@link ValueConverter}.
114         *
115         * @return the 'from' type
116         */
117        @Nonnull
118        public Type getFromType() {
119                return this.fromType;
120        }
121
122        /**
123         * The 'from' value of the failed {@link ValueConverter}.
124         *
125         * @return the 'from' value that could not be converted to the 'to' type
126         */
127        @Nonnull
128        public Optional<Object> getFromValue() {
129                return Optional.ofNullable(this.fromValue);
130        }
131
132        /**
133         * The 'to' type of the failed {@link ValueConverter}.
134         *
135         * @return the 'to' type
136         */
137        @Nonnull
138        public Type getToType() {
139                return this.toType;
140        }
141}