我已经解决了上面发布的问题,并在此处发布了我的解决方案以供参考。
在发布导致错误的原因之前,我想显示 由我的应用程序的dispatcher Servlet加载的 上下文文件。
<?xml version='1.0' encoding='UTF-8'?><beans xmlns='http://www.springframework.org/schema/beans' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:context='http://www.springframework.org/schema/context' xmlns:mvc='http://www.springframework.org/schema/mvc' xmlns:tx='http://www.springframework.org/schema/tx' xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd'><context:annotation-config /><context:component-scan base-package='<MY-PACKAGES>' /><!-- Handles GET requests for /resources/** by efficiently serving static content in the ${webappRoot}/resources dir --><mvc:resources location='/resources/' mapping='/resources/**'/><!-- This tag registers the HandlerMapping and HandlerAdapter required to dispatch requests to your @Controllers. In addition, it applies sensible defaults based on what is present in your classpath. Such defaults include: 1) Using the Spring 3 Type ConversionService as a simpler and more robust alternative to JavaBeans propertyeditors 2) Support for formatting Number fields with @NumberFormat 3) Support for formatting Date, Calendar, and Joda Time fields with @DateTimeFormat, if Joda Time is on the classpath 4) Support for validating @Controller inputs with @Valid, if a JSR-303 Provider is on the classpath 5) Support for reading and writing XML, if JAXB is on the classpath 6) Support for reading and writing JSON, if Jackson is on the classpath --><mvc:annotation-driven/><mvc:interceptors> <bean class='org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor'> <property name='sessionFactory'> <ref bean='sessionFactory'/> </property> <property name='singleSession' value='false' /> </bean></mvc:interceptors><!-- Without the following adapter, we’ll get a 'Does your handler implement a supported interface like Controller?' This is because mvc:annotation-driven element doesn’t declare a SimpleControllerHandlerAdapter For more info See http://stackoverflow.com/questions/3896013/no-adapter-for-handler-exception See http://forum.springsource.org/showthread.PHP?t=48372&highlight=UrlFilenameViewController --><bean /><!-- org.springframework.web.servlet.view.ResourceBundleViewResolver The bundle is typically defined in a properties file, located in the class path. The default bundle basename is 'views'. --><bean class='org.springframework.web.servlet.view.ResourceBundleViewResolver'> <property name='basename' value='views' /></bean></beans>
从上面的文件中可以看出,我使用了 *
在spring容器初始化时,属性值org.springframework.web.bind.support.ConfigurableWebBindingInitializer.setConversionService(ConversionService)被设置为 org.springframework.format.support.FormattingConversionService 的实例,而不是org.springframework.core我 在其中注册了我的自定义转换器的.convert.support.GenericConversionService ,因此引发了错误, 。
但是到目前为止,我的应用程序中不需要格式转换服务,只想注册我的自定义转换器,因此为了实现我的目标,我使用了如下所示的更新代码:
<?xml version='1.0' encoding='UTF-8'?><beans xmlns='http://www.springframework.org/schema/beans' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:context='http://www.springframework.org/schema/context' xmlns:mvc='http://www.springframework.org/schema/mvc' xmlns:tx='http://www.springframework.org/schema/tx' xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd'><context:annotation-config /><context:component-scan base-package='<MY-PACKAGES>' /><!-- Handles GET requests for /resources/** by efficiently serving static content in the ${webappRoot}/resources dir --><mvc:resources location='/resources/' mapping='/resources/**'/><!-- This tag registers the HandlerMapping and HandlerAdapter required to dispatch requests to your @Controllers. In addition, it applies sensible defaults based on what is present in your classpath. Such defaults include: 1) Using the Spring 3 Type ConversionService as a simpler and more robust alternative to JavaBeans propertyeditors 2) Support for formatting Number fields with @NumberFormat 3) Support for formatting Date, Calendar, and Joda Time fields with @DateTimeFormat, if Joda Time is on the classpath 4) Support for validating @Controller inputs with @Valid, if a JSR-303 Provider is on the classpath 5) Support for reading and writing XML, if JAXB is on the classpath 6) Support for reading and writing JSON, if Jackson is on the classpath --> <!-- We just require the converter feature not the formatting feature.Thus registering only the org.springframework.core.convert.support.GenericConversionService and not org.springframework.format.support.FormattingConversionService which <mvc:annotation-driven> activates by default.Also we are registering a custom converter using the com.flightnetwork.cars.controller.util.ConverterConfig class --><!-- Added this to resolve my issue --><mvc:annotation-driven conversion-service='conversionService'/><mvc:interceptors> <bean class='org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor'> <property name='sessionFactory'> <ref bean='sessionFactory'/> </property> <property name='singleSession' value='false' /> </bean></mvc:interceptors><!-- Without the following adapter, we’ll get a 'Does your handler implement a supported interface like Controller?' This is because mvc:annotation-driven element doesn’t declare a SimpleControllerHandlerAdapter For more info See http://stackoverflow.com/questions/3896013/no-adapter-for-handler-exception See http://forum.springsource.org/showthread.PHP?t=48372&highlight=UrlFilenameViewController --><bean /><!-- org.springframework.web.servlet.view.ResourceBundleViewResolver The bundle is typically defined in a properties file, located in the class path. The default bundle basename is 'views'. --><bean class='org.springframework.web.servlet.view.ResourceBundleViewResolver'> <property name='basename' value='views' /></bean><!-- Added this to resolve my issue --><bean /></beans>
import java.util.Collections; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.ConverterRegistry; import org.springframework.core.convert.support.ConversionServiceFactory; @Configuration public class ConverterConfig {@Autowiredprivate ConversionService conversionService;@Autowiredprivate ConverterRegistry converterRegistry;@Bean@DependsOn(value='conversionService')public StringToMapConverter stringToMapConverter() { StringToMapConverter stringToMapConverter = new StringToMapConverter(); stringToMapConverter.setConversionService(this.conversionService); ConversionServiceFactory.registerConverters( Collections.singleton(stringToMapConverter), this.converterRegistry); return stringToMapConverter;} }解决方法
我创建了一个StringToMapConverter,用于将预定义格式的字符串转换为键值对的Map。键也可以是Enum类型。
但是在转换器中,我需要引用org.springframework.core.convert.ConversionService实例以将字符串转换为枚举,因此在myapp-servlet.xml上下文中尝试注册如下:
<bean /><bean class='org.springframework.context.support.ConversionServiceFactoryBean'><property name='converters'> <bean ref='stringToMapConverter' /></property></bean>
这使我陷入循环依赖错误,例如 “ conversionService:FactoryBean,当前正在创建中,它从getObject返回null”。
因此,我尝试使用带有@Configuration注释的ConverterConverter类(我在下面提供的代码)来解决此循环依赖项错误,但现在我面临以下错误。
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errorsField error in object ’searchResultsRefiner’ on field ’filtersMap’: rejected value []; codes [typeMismatch.searchResultsRefiner.filtersMap,typeMismatch.filtersMap,typeMismatch.java.util.Map,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [searchResultsRefiner.filtersMap,filtersMap]; arguments []; default message [filtersMap]]; default message [Failed to convert property value of type ’java.lang.String’ to required type ’java.util.Map’ for property ’filtersMap’; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [java.util.Map] for property ’filtersMap’: no matching editors or conversion strategy found] at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doBind(HandlerMethodInvoker.java:810) at or
我调试了应用程序,发现转换器已成功添加到寄存器中,但是当需要数据从java.lang.String转换为java.util.Map时,框架仍然找不到它。
下面提到的是我编写的代码:
SearchResultsRefiner.java
public class SearchResultsRefiner { private Map<SearchRefineFilter,String> filtersMap; public SearchResultsRefiner() {} public Map<SearchRefineFilter,String> getFiltersMap() {return filtersMap; } public void setFiltersMap(Map<SearchRefineFilter,String> filtersMap) {this.filtersMap = filtersMap; } }
ConverterConfig.java
import java.util.Collections; @Configuration public class ConverterConfig { private ConversionService conversionService; private ConverterRegistry converterRegistry; @Bean public ConversionService conversionService() {this.conversionService = ConversionServiceFactory.createDefaultConversionService();this.converterRegistry = (GenericConversionService) this.conversionService;return conversionService; } @Bean @DependsOn(value='conversionService') public StringToMapConverter stringToMapConverter() {StringToMapConverter stringToMapConverter = new StringToMapConverter();stringToMapConverter.setConversionService(this.conversionService);ConversionServiceFactory.registerConverters(Collections.singleton(stringToMapConverter),this.converterRegistry);return stringToMapConverter; } }
服务器启动日志
2012-01-19 20:37:08,108 INFO [ContextLoader] Root WebApplicationContext: initialization started 2012-01-19 20:37:08,142 INFO [XmlWebApplicationContext] Refreshing Root WebApplicationContext: startup date [Thu Jan 19 20:37:08 IST 2012]; root of context hierarchy 2012-01-19 20:37:08,201 INFO [XmlBeanDefinitionReader] Loading XML bean definitions from ServletContext resource [/WEB-INF/spring/util-context.xml] 2012-01-19 20:37:08,342 INFO [XmlBeanDefinitionReader] Loading XML bean definitions from ServletContext resource [/WEB-INF/spring/service-context.xml] 2012-01-19 20:37:08,677 INFO [XmlBeanDefinitionReader] Loading XML bean definitions from ServletContext resource [/WEB-INF/spring/persistence-context.xml] 2012-01-19 20:37:09,215 INFO [PropertyPlaceholderConfigurer] Loading properties file from class path resource [fn-cars-bundle.properties] 2012-01-19 20:37:09,221 INFO [PropertyPlaceholderConfigurer] Loading properties file from class path resource [fn-cars-bundle.properties] 2012-01-19 20:37:09,233 INFO [DwrAnnotationPostProcessor] Detected candidate bean [asynchronousRequestHandlerServiceImpl]. Remoting using AsyncService 2012-01-19 20:37:09,246 INFO [DwrAnnotationPostProcessor] Could not infer class for [conversionService]. Is it a factory bean? Omitting bean from annotation processing 2012-01-19 20:37:09,246 INFO [DwrAnnotationPostProcessor] Could not infer class for [stringToMapConverter]. Is it a factory bean? Omitting bean from annotation processing 2012-01-19 20:37:09,436 INFO [DefaultListableBeanFactory] Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@aae8a: defining beans [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,messageSource,memcachedClient,velocityEngine,smtpAuthenticator,mailSession,mailSender,converterConfig,resourceBundleUtil,dwrAnnotationPostProcessor,org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#1,locationDAO,dataSource,sessionFactory,txManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,conversionService,stringToMapConverter,__AsyncService,__dwrConfiguration]; root of factory hierarchy
StringToMapConverter
public class StringToMapConverter implements ConditionalGenericConverter { private static final String COMMA = ','; private static final String COLON = ':'; private ConversionService conversionService; /** * @param conversionService the conversionService to set */ public void setConversionService(ConversionService conversionService) {this.conversionService = conversionService; } @Override public Set<ConvertiblePair> getConvertibleTypes() {return Collections.singleton(new ConvertiblePair(String.class,Map.class)); } @Override public boolean matches(TypeDescriptor sourceType,TypeDescriptor targetType) {boolean matches = this.conversionService.canConvert(sourceType,targetType.getMapKeyTypeDescriptor()) && this.conversionService.canConvert(sourceType,targetType.getMapValueTypeDescriptor());return matches; } @SuppressWarnings('unchecked') @Override public Object convert(Object source,TypeDescriptor sourceType,TypeDescriptor targetType) {if (source == null) { return null;}String sourceString = (String) source;if (sourceString.trim().isEmpty()) { return Collections.emptyMap();}@SuppressWarnings('rawtypes')Map targetMap = new HashMap();String[] keyValuePairs = sourceString.split(COMMA);String[] keyValueArr = null;String key = null;String value = null;for (String keyValuePair : keyValuePairs) { keyValueArr = keyValuePair.split(COLON); key = keyValueArr[0].trim(); value = keyValueArr[1].trim(); Object targetKey = this.conversionService.convert( key,sourceType,targetType.getMapKeyTypeDescriptor(key)); targetMap.put(targetKey,value);}return targetMap; }}
有人可以解释一下这种现象的原因吗,因为如上面所示的服务器启动日志中所示,创建了 stringToMapConverterbean以及如何解决该问题?
谢谢,吉涅什