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.beans; 018 019import java.beans.PropertyChangeEvent; 020 021import org.springframework.lang.Nullable; 022import org.springframework.util.Assert; 023import org.springframework.util.ClassUtils; 024 025/** 026 * Exception thrown on a type mismatch when trying to set a bean property. 027 * 028 * @author Rod Johnson 029 * @author Juergen Hoeller 030 */ 031@SuppressWarnings("serial") 032public class TypeMismatchException extends PropertyAccessException { 033 034 /** 035 * Error code that a type mismatch error will be registered with. 036 */ 037 public static final String ERROR_CODE = "typeMismatch"; 038 039 040 @Nullable 041 private String propertyName; 042 043 @Nullable 044 private transient Object value; 045 046 @Nullable 047 private Class<?> requiredType; 048 049 050 /** 051 * Create a new {@code TypeMismatchException}. 052 * @param propertyChangeEvent the PropertyChangeEvent that resulted in the problem 053 * @param requiredType the required target type 054 */ 055 public TypeMismatchException(PropertyChangeEvent propertyChangeEvent, Class<?> requiredType) { 056 this(propertyChangeEvent, requiredType, null); 057 } 058 059 /** 060 * Create a new {@code TypeMismatchException}. 061 * @param propertyChangeEvent the PropertyChangeEvent that resulted in the problem 062 * @param requiredType the required target type (or {@code null} if not known) 063 * @param cause the root cause (may be {@code null}) 064 */ 065 public TypeMismatchException(PropertyChangeEvent propertyChangeEvent, @Nullable Class<?> requiredType, 066 @Nullable Throwable cause) { 067 068 super(propertyChangeEvent, 069 "Failed to convert property value of type '" + 070 ClassUtils.getDescriptiveType(propertyChangeEvent.getNewValue()) + "'" + 071 (requiredType != null ? 072 " to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : "") + 073 (propertyChangeEvent.getPropertyName() != null ? 074 " for property '" + propertyChangeEvent.getPropertyName() + "'" : ""), 075 cause); 076 this.propertyName = propertyChangeEvent.getPropertyName(); 077 this.value = propertyChangeEvent.getNewValue(); 078 this.requiredType = requiredType; 079 } 080 081 /** 082 * Create a new {@code TypeMismatchException} without a {@code PropertyChangeEvent}. 083 * @param value the offending value that couldn't be converted (may be {@code null}) 084 * @param requiredType the required target type (or {@code null} if not known) 085 * @see #initPropertyName 086 */ 087 public TypeMismatchException(@Nullable Object value, @Nullable Class<?> requiredType) { 088 this(value, requiredType, null); 089 } 090 091 /** 092 * Create a new {@code TypeMismatchException} without a {@code PropertyChangeEvent}. 093 * @param value the offending value that couldn't be converted (may be {@code null}) 094 * @param requiredType the required target type (or {@code null} if not known) 095 * @param cause the root cause (may be {@code null}) 096 * @see #initPropertyName 097 */ 098 public TypeMismatchException(@Nullable Object value, @Nullable Class<?> requiredType, @Nullable Throwable cause) { 099 super("Failed to convert value of type '" + ClassUtils.getDescriptiveType(value) + "'" + 100 (requiredType != null ? " to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : ""), 101 cause); 102 this.value = value; 103 this.requiredType = requiredType; 104 } 105 106 107 /** 108 * Initialize this exception's property name for exposure through {@link #getPropertyName()}, 109 * as an alternative to having it initialized via a {@link PropertyChangeEvent}. 110 * @param propertyName the property name to expose 111 * @since 5.0.4 112 * @see #TypeMismatchException(Object, Class) 113 * @see #TypeMismatchException(Object, Class, Throwable) 114 */ 115 public void initPropertyName(String propertyName) { 116 Assert.state(this.propertyName == null, "Property name already initialized"); 117 this.propertyName = propertyName; 118 } 119 120 /** 121 * Return the name of the affected property, if available. 122 */ 123 @Override 124 @Nullable 125 public String getPropertyName() { 126 return this.propertyName; 127 } 128 129 /** 130 * Return the offending value (may be {@code null}). 131 */ 132 @Override 133 @Nullable 134 public Object getValue() { 135 return this.value; 136 } 137 138 /** 139 * Return the required target type, if any. 140 */ 141 @Nullable 142 public Class<?> getRequiredType() { 143 return this.requiredType; 144 } 145 146 @Override 147 public String getErrorCode() { 148 return ERROR_CODE; 149 } 150 151}