Неожиданное исключение зафиксировало установку «xxx» в «классе xxx: ошибка установки выражения «xxx» со значением ['x', ]

Я передаю некоторые параметры классу действий, реализующему ModelDriven<Transporter>, через строку запроса.

<s:form namespace="/admin_side" action="Test" id="dataForm" name="dataForm">
    <s:url id="editURL" action="EditTest" escapeAmp="false">
        <s:param name="transporterId" value="1"/>
        <s:param name="transporterName" value="'DHL'"/>
    </s:url>
    <s:a href="%{editURL}">Click</s:a>
</s:form>

Класс действий следующий.

@Namespace("/admin_side")
@ResultPath("/WEB-INF/content")
@ParentPackage(value = "struts-default")
public final class TestAction extends ActionSupport 
                           implements Serializable, Preparable, ModelDriven<Transporter>
{
    private static final long serialVersionUID = 1L;
    private Transporter transporter = new Transporter();

    @Action(value = "Test",
    results = {
        @Result(name = ActionSupport.SUCCESS, location = "Test.jsp"),
        @Result(name = ActionSupport.INPUT, location = "Test.jsp")},
    interceptorRefs = {
        @InterceptorRef(value = "paramsPrepareParamsStack", 
                 params = {"params.acceptParamNames", "transporterId, transporterName"})})
    public String load() throws Exception {
        return ActionSupport.SUCCESS;
    }

    @Action(value = "EditTest",
    results = {
        @Result(name = ActionSupport.SUCCESS, location = "Test.jsp"),
        @Result(name = ActionSupport.INPUT, location = "Test.jsp")},
    interceptorRefs = {
        @InterceptorRef(value = "paramsPrepareParamsStack", 
                 params = {"params.acceptParamNames", "transporterId, transporterName"})})
    public String edit() {
        System.out.println(transporter.getTransporterId() 
                         + " : " + transporter.getTransporterName());
        return ActionSupport.SUCCESS;
    }

    @Override
    public Transporter getModel() {
        return transporter;
    }

    @Override
    public void prepare() throws Exception {}
}

Серверный терминал отображает следующие сообщения.

Jan 09, 2014 4:06:32 PM com.opensymphony.xwork2.interceptor.ParametersInterceptor error
SEVERE: Developer Notification (set struts.devMode to false to disable this message):
Unexpected Exception caught setting 'transporterId' on 'class actions.TestAction: Error setting expression 'transporterId' with value ['1', ]
Jan 09, 2014 4:06:32 PM com.opensymphony.xwork2.interceptor.ParametersInterceptor error
SEVERE: Developer Notification (set struts.devMode to false to disable this message):
Unexpected Exception caught setting 'transporterName' on 'class actions.TestAction: Error setting expression 'transporterName' with value ['DHL', ]

Несмотря на то, что уровень журнала SEVERE, значения этих параметров доступны в классе действий как

System.out.println(transporter.getTransporterId() 
                 + " : " + transporter.getTransporterName());

в методе edit().

Если paramsPrepareParamsStack заменить на defaultStack, то эти сообщения исчезнут.

Такие выражения, как ['DHL', ], указывают на массив. transporterId и transporterName в модели относятся к типу Long и String соответственно.

Что я делаю не так?


person Tiny    schedule 09.01.2014    source источник


Ответы (2)


Здесь нет проблемы с массивом (даже если так кажется): такое исключение означает, что Struts не может найти сеттер для вашего параметра:

Из документации ParametersInterceptor:

Предупреждение об отсутствующих параметрах

Если нет установщика для данного имени параметра, в devMode будет зарегистрировано предупреждающее сообщение, подобное приведенному ниже:

SEVERE: Developer Notification (set struts.devMode to false to disable this 
message):
Unexpected Exception caught setting 'search' on 'class demo.ItemSearchAction: 
Error setting expression 'search' with value ['search', ]
Error setting expression 'search' with value ['search', ] - [unknown location] 
  at com.opensymphony.xwork2.ognl.OgnlValueStack.handleRuntimeException(OgnlValueStack.java:201)
  at com.opensymphony.xwork2.ognl.OgnlValueStack.setValue(OgnlValueStack.java:178)
  at com.opensymphony.xwork2.ognl.OgnlValueStack.setParameter(OgnlValueStack.java:152)

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

Вы можете легко воспроизвести эту ошибку, поместив в JSP элемент, который не существует в действии.

Поскольку ваши свойства существуют (с их сеттерами) в модели, и вы используете ModelDriven и paramsPrepareParamsStack, я думаю, что происходит следующее:

  • ModelDriven Interceptor делегирован для обработки объекта модели;
  • В первый раз, когда вы вызываете Parameters Interceptor, ModelDriven Interceptor еще не запущено;
  • Тогда ваше действие ничего не знает об объекте модели и попытайтесь найти сеттеры для ваших параметров в действии, а НЕ в модели.
  • Вместо этого второй перехватчик запускается после ModelDriven и точно знает, где устанавливать параметры. Вот почему у вас правильно установлены параметры в методе Action.

Но если это так, то вы НЕ должны получить эти параметры в методе prepare() (именно поэтому вы используете этот стек...):
пожалуйста, попробуйте и выложи сюда результат.

Первое, что приходит мне в голову, чтобы решить эту проблему, это поместить ModelDriven Interceptor перед первым Parameters Interceptor (либо скопировав его, либо переместив, я не уверен, какой побочный эффект, если таковой вообще имеется, это может вызвать в обоих случаях вы должны снова попытаться сообщить об этом здесь).

Затем определите следующий стек и используйте его.

<interceptor-stack name="modelParamsPrepareParamsStack">
    <interceptor-ref name="exception"/>
    <interceptor-ref name="alias"/>
    <interceptor-ref name="i18n"/>
    <interceptor-ref name="checkbox"/>
    <interceptor-ref name="multiselect"/>

    <!-- NEW ModelDriven Position -->
    <interceptor-ref name="modelDriven"/>

    <interceptor-ref name="params">
        <param name="excludeParams">^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>
    </interceptor-ref>
    <interceptor-ref name="servletConfig"/>
    <interceptor-ref name="prepare"/>
    <interceptor-ref name="chain"/>

    <!-- OLD ModelDriven Position -->
    <!--interceptor-ref name="modelDriven"/-->

    <interceptor-ref name="fileUpload"/>
    <interceptor-ref name="staticParams"/>
    <interceptor-ref name="actionMappingParams"/>
    <interceptor-ref name="params">
        <param name="excludeParams">^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>
    </interceptor-ref>
    <interceptor-ref name="conversionError"/>
    <interceptor-ref name="validation">
        <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
    <interceptor-ref name="workflow">
        <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
</interceptor-stack>

Надеюсь, это поможет.

person Andrea Ligios    schedule 09.01.2014
comment
При использовании paramsPrepareParamsStack вместе с ModelDriven<T extends Object> значения поля/свойства в модели были недоступны в методе prepare(). Используя этот стек, эти сообщения растворились в воздухе, значения модели также доступны в методе prepare(). - person Tiny; 09.01.2014

В приведенном вами коде я не могу найти объявление класса Transporter.

Так что я предполагаю, что, возможно, это потому, что ваш класс Transpoter имеет больше параметров, чем 2, а не только идентификатор и имя.

Фактически, это сообщение об ошибке всегда появлялось в ситуации, о которой я упоминал.

Чтобы решить эту проблему, вы можете определить объект передачи данных (DTO), который имеет только 2 атрибута: идентификатор и имя. Используйте этот DTO для приема параметров из jsp, а затем передайте значение атрибута объекту Transporter.

Я вижу эти проблемы в 2019 году и предлагаю решение, надеясь, что оно может быть полезно другим в будущем.

person ghshan    schedule 16.04.2019