Связывание Spring 3.0 MVC перечисления чувствительны к регистру - PullRequest
49 голосов
/ 06 января 2011

Если у меня есть RequestMapping в контроллере Spring, как это ...

@RequestMapping(method = RequestMethod.GET, value = "{product}")
public ModelAndView getPage(@PathVariable Product product)

И продукт - это перечисление. например. Product.Home

Когда я запрашиваю страницу, mysite.com/home

Я получаю

Unable to convert value "home" from type 'java.lang.String' to type 'domain.model.product.Product'; nested exception is java.lang.IllegalArgumentException: No enum const class domain.model.product.Product.home

Есть ли способ получить преобразователь типа enum, чтобы понять, что строчные буквы home на самом деле Home?

Я бы хотел, чтобы в URL-адресе не учитывался регистр, а в моих перечислениях Java используются стандартные заглавные буквы.

Спасибо

Решение

public class ProductEnumConverter extends PropertyEditorSupport
{
    @Override public void setAsText(final String text) throws IllegalArgumentException
    {
        setValue(Product.valueOf(WordUtils.capitalizeFully(text.trim())));
    }
}

регистрация

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <entry key="domain.model.product.Product" value="domain.infrastructure.ProductEnumConverter"/>
            </map>
        </property>
    </bean>

Добавить к контроллерам, которые нуждаются в специальном преобразовании

@InitBinder
public void initBinder(WebDataBinder binder)
{
    binder.registerCustomEditor(Product.class, new ProductEnumConverter());
} 

Ответы [ 5 ]

23 голосов
/ 06 января 2011

Вообще говоря, вы хотите создать новый PropertyEditor, который выполняет нормализацию за вас, и затем вы регистрируете это в своем контроллере следующим образом:

@InitBinder
 public void initBinder(WebDataBinder binder) {

  binder.registerCustomEditor(Product.class,
    new CaseInsensitivePropertyEditor());
 }
17 голосов
/ 06 января 2011

Я думаю, вам придется реализовать пользовательский PropertyEditor .

Примерно так:

public class ProductEditor extends PropertyEditorSupport{

    @Override
    public void setAsText(final String text){
        setValue(Product.valueOf(text.toUpperCase()));
    }

}

См. Ответ GaryF о том, какчтобы связать его

Вот более терпимая версия, если вы используете строчные буквы в константах перечисления (что, вероятно, не следует, но все же):

@Override
public void setAsText(final String text){
    Product product = null;
    for(final Product candidate : Product.values()){
        if(candidate.name().equalsIgnoreCase(text)){
            product = candidate;
            break;
        }
    }
    setValue(product);
}
13 голосов
/ 03 июня 2015

Также возможно создать универсальный конвертер, который будет работать со всеми перечислениями следующим образом:

public class CaseInsensitiveConverter<T extends Enum<T>> extends PropertyEditorSupport {

    private final Class<T> typeParameterClass;

    public CaseInsensitiveConverter(Class<T> typeParameterClass) {
        super();
        this.typeParameterClass = typeParameterClass;
    }

    @Override
    public void setAsText(final String text) throws IllegalArgumentException {
        String upper = text.toUpperCase(); // or something more robust
        T value = T.valueOf(typeParameterClass, upper);
        setValue(value);
    }
}

Использование:

@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.registerCustomEditor(MyEnum.class, new CaseInsensitiveConverter<>(MyEnum.class));
}

Или глобально, как объясняет Скаффман

7 голосов
/ 06 января 2011

Чтобы добавить ответ @ GaryF и добавить к нему свой комментарий, вы можете объявить глобальные редакторы пользовательских свойств, вставив их в пользовательский AnnotationMethodHandlerAdapter. Spring MVC обычно регистрирует один из них по умолчанию, но вы можете назначить его специально настроенным, например,

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
  <property name="webBindingInitializer">
    <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
      <property name="propertyEditorRegistrars">
        <list>
          <bean class="com.xyz.MyPropertyEditorRegistrar"/>
        </list>
      </property>
    </bean>
  </property>
</bean>

MyPropertyEditorRegistrar является экземпляром PropertyEditorRegistrar, который, в свою очередь, регистрирует пользовательские PropertyEditor объекты в Spring.

Простого объявления этого должно быть достаточно.

6 голосов
/ 25 октября 2018

В Spring Boot 2 вы можете использовать ApplicationConversionService. Он предоставляет несколько полезных конвертеров, особенно org.springframework.boot.convert.StringToEnumIgnoringCaseConverterFactory, отвечающих за преобразование строкового значения в экземпляр enum. Это самое общее (нам не нужно создавать отдельный конвертер / форматтер для каждого перечисления) и самое простое решение, которое мне удалось найти.

import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class AppWebMvcConfigurer implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        ApplicationConversionService.configure(registry);
    }
}

Я знаю, что вопросы касаются Spring 3, но это первый результат в Google при поиске фразы spring mvc enums case insensitive.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...