001/* 002 * Copyright 2012-2017 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.autoconfigure.validation; 018 019import org.springframework.beans.BeansException; 020import org.springframework.beans.factory.DisposableBean; 021import org.springframework.beans.factory.InitializingBean; 022import org.springframework.beans.factory.NoSuchBeanDefinitionException; 023import org.springframework.boot.validation.MessageInterpolatorFactory; 024import org.springframework.context.ApplicationContext; 025import org.springframework.context.ApplicationContextAware; 026import org.springframework.validation.Errors; 027import org.springframework.validation.SmartValidator; 028import org.springframework.validation.Validator; 029import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean; 030import org.springframework.validation.beanvalidation.SpringValidatorAdapter; 031 032/** 033 * {@link Validator} implementation that delegates calls to another {@link Validator}. 034 * This {@link Validator} implements Spring's {@link SmartValidator} interface but does 035 * not implement the JSR-303 {@code javax.validator.Validator} interface. 036 * 037 * @author Stephane Nicoll 038 * @author Phillip Webb 039 * @since 2.0.0 040 */ 041public class ValidatorAdapter implements SmartValidator, ApplicationContextAware, 042 InitializingBean, DisposableBean { 043 044 private final SmartValidator target; 045 046 private final boolean existingBean; 047 048 ValidatorAdapter(SmartValidator target, boolean existingBean) { 049 this.target = target; 050 this.existingBean = existingBean; 051 } 052 053 public final Validator getTarget() { 054 return this.target; 055 } 056 057 @Override 058 public boolean supports(Class<?> clazz) { 059 return this.target.supports(clazz); 060 } 061 062 @Override 063 public void validate(Object target, Errors errors) { 064 this.target.validate(target, errors); 065 } 066 067 @Override 068 public void validate(Object target, Errors errors, Object... validationHints) { 069 this.target.validate(target, errors, validationHints); 070 } 071 072 @Override 073 public void setApplicationContext(ApplicationContext applicationContext) 074 throws BeansException { 075 if (!this.existingBean && this.target instanceof ApplicationContextAware) { 076 ((ApplicationContextAware) this.target) 077 .setApplicationContext(applicationContext); 078 } 079 } 080 081 @Override 082 public void afterPropertiesSet() throws Exception { 083 if (!this.existingBean && this.target instanceof InitializingBean) { 084 ((InitializingBean) this.target).afterPropertiesSet(); 085 } 086 } 087 088 @Override 089 public void destroy() throws Exception { 090 if (!this.existingBean && this.target instanceof DisposableBean) { 091 ((DisposableBean) this.target).destroy(); 092 } 093 } 094 095 /** 096 * Return a {@link Validator} that only implements the {@link Validator} interface, 097 * wrapping it if necessary. 098 * <p> 099 * If the specified {@link Validator} is not {@code null}, it is wrapped. If not, a 100 * {@link javax.validation.Validator} is retrieved from the context and wrapped. 101 * Otherwise, a new default validator is created. 102 * @param applicationContext the application context 103 * @param validator an existing validator to use or {@code null} 104 * @return the validator to use 105 */ 106 public static Validator get(ApplicationContext applicationContext, 107 Validator validator) { 108 if (validator != null) { 109 return wrap(validator, false); 110 } 111 return getExistingOrCreate(applicationContext); 112 } 113 114 private static Validator getExistingOrCreate(ApplicationContext applicationContext) { 115 Validator existing = getExisting(applicationContext); 116 if (existing != null) { 117 return wrap(existing, true); 118 } 119 return create(); 120 } 121 122 private static Validator getExisting(ApplicationContext applicationContext) { 123 try { 124 javax.validation.Validator validator = applicationContext 125 .getBean(javax.validation.Validator.class); 126 if (validator instanceof Validator) { 127 return (Validator) validator; 128 } 129 return new SpringValidatorAdapter(validator); 130 } 131 catch (NoSuchBeanDefinitionException ex) { 132 return null; 133 } 134 } 135 136 private static Validator create() { 137 OptionalValidatorFactoryBean validator = new OptionalValidatorFactoryBean(); 138 validator.setMessageInterpolator(new MessageInterpolatorFactory().getObject()); 139 return wrap(validator, false); 140 } 141 142 private static Validator wrap(Validator validator, boolean existingBean) { 143 if (validator instanceof javax.validation.Validator) { 144 if (validator instanceof SpringValidatorAdapter) { 145 return new ValidatorAdapter((SpringValidatorAdapter) validator, 146 existingBean); 147 } 148 return new ValidatorAdapter( 149 new SpringValidatorAdapter((javax.validation.Validator) validator), 150 existingBean); 151 } 152 return validator; 153 } 154 155}