Весна. Передача строковых значений из View в int / Integer параметры в Model - PullRequest
0 голосов
/ 31 октября 2019

Я учусь весне, и я столкнулся со странным поведением, которое не могу объяснить. Здесь у меня есть простой класс:

public class Customer {
    private Integer id;

    public void setId(Integer id) {
        this.id = id;
    }

Простой контроллер:

@Controller
@RequestMapping("/customer")
public class CustomerController {

    @InitBinder
    public void initBinder(WebDataBinder dataBinder){
        StringTrimmerEditor editor = new StringTrimmerEditor(true);
        dataBinder.registerCustomEditor(String.class,editor);
    }

    @RequestMapping("/showForm")
    public String customerPage(Model model){
        model.addAttribute("customer",new Customer());
        return "customerPage";
    }
    @RequestMapping("/showConfirmation")
    public String customerConfirmation(@Valid @ModelAttribute("customer") Customer customer, BindingResult result){
        System.out.println(customer.getLastName());
        if(result.hasErrors())
            return "customerPage";
        else
            return "customerConfirmation";
    }
}

А вот часть customerPage.jsp:

<body>
    <form:form action="showConfirmation" modelAttribute="customer">
        Id: <form:input path="id"/>
        <form:errors path="id"/>
        <input type="submit" value="Submit">
    </form:form>
</body>

Я запускаю его, оставляюпустое поле id и нажмите кнопку "Отправить".

Если мое свойство Customer.id имеет значение Integer, я получаю следующую последовательность действий: метод initBinder запускает и устанавливает для моей пустой строки значение NULL. Затем срабатывает setterMethod, устанавливает id в null, все хорошо.

Но если Customer.id имеет тип int, то в браузере я получаю следующее: NumberFormatException: Для входной строки: "" . Вопрос в том, почему входная строка в исключении просто пуста? Разве initBinder не должен был установить входную строку в ноль к этому моменту? Я думал, что последовательность всегда выглядит следующим образом: методы @InitBinder → методы установки → проверка установленных значений.

результат → ошибки → источник → причина → stackTrace:

"java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:68)"
"java.base/java.lang.Integer.parseInt(Integer.java:668)"
"java.base/java.lang.Integer.valueOf(Integer.java:989)"
"org.springframework.util.NumberUtils.parseNumber(NumberUtils.java:211)"
"org.springframework.beans.propertyeditors.CustomNumberEditor.setAsText(CustomNumberEditor.java:115)"
"org.springframework.beans.TypeConverterDelegate.doConvertTextValue(TypeConverterDelegate.java:429)"
"org.springframework.beans.TypeConverterDelegate.doConvertValue(TypeConverterDelegate.java:402)"
"org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:155)"
"org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:585)"
"org.springframework.beans.AbstractNestablePropertyAccessor.convertForProperty(AbstractNestablePropertyAccessor.java:604)"
"org.springframework.beans.AbstractNestablePropertyAccessor.processLocalProperty(AbstractNestablePropertyAccessor.java:453)"
"org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:278)"
"org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:266)"
"org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:97)"
"org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:848)"
"org.springframework.validation.DataBinder.doBind(DataBinder.java:744)"
"org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:197)"
"org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:107)"
"org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.bindRequestParameters(ServletModelAttributeMethodProcessor.java:158)"
"org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:160)"
"org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)"
"org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167)"
"org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)"
"org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)"
"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)"
"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)"
"org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)"
"org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)"
"org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)"
"org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)"
"org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)"
"javax.servlet.http.HttpServlet.service(HttpServlet.java:660)"
"org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)"
"javax.servlet.http.HttpServlet.service(HttpServlet.java:741)"
"org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)"
"org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)"
"org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)"
"org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)"
"org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)"
"org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)"
"org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)"
"org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)"
"org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)"
"org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)"
"org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:678)"
"org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)"
"org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)"
"org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)"
"org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)"
"org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)"
"org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1579)"
"org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)"
"java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)"
"java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)"
"org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)"
"java.base/java.lang.Thread.run(Thread.java:830)"

1 Ответ

0 голосов
/ 31 октября 2019

Глядя на код для setAsText в CustomNumberEditor на момент написания:

@Override
public void setAsText(String text) throws IllegalArgumentException {
    if (this.allowEmpty && !StringUtils.hasText(text)) {
        // Treat empty String as null value.
        setValue(null);
    }
    else if (this.numberFormat != null) {
        // Use given NumberFormat for parsing text.
        setValue(NumberUtils.parseNumber(text, this.numberClass, this.numberFormat));
    }
    else {
        // Use default valueOf methods for parsing text.
        setValue(NumberUtils.parseNumber(text, this.numberClass));
    }
}

Мы видим, что если свойство allowEmpty имеет значение true он установит значение как ноль, когда текст будет нулевым или пустой строкой. Если значение равно false , оно просто попытается проанализировать числовое значение из строки независимо, что приведет к ошибке. Без углубления в код, разумно, чтобы флаг allowEmpty был установлен на false , вероятно, потому что int является примитивом и не может быть нулевым. Это может показаться нежелательным, но когда int не назначен, по умолчанию он обнуляется. Вы бы предпочли, чтобы генерировалось исключение, а не значение int, равное 0, так как это будет просто скрывать ошибки.

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