简体   繁体   English

Wicket SpringBean在一个面板上生成NotSerializableException,但在另一个面板上不生成

[英]Wicket SpringBean generates NotSerializableException on one panel but not another

I have a spring bean DAO class, that has a method reverseLookup() which returns a List<String>. 我有一个Spring bean DAO类,它具有方法reverseLookup(),该方法返回List <String>。 I inject this bean into 2 wicket components, and make a call to the same method in an ajax call on each component. 我将此bean注入2个wicket组件中,并在每个组件的ajax调用中调用相同的方法。

In the first panel, it works fine with no problems. 在第一个面板中,它工作正常,没有任何问题。 In the second panel, I get a NotSerializableException. 在第二个面板中,我收到一个NotSerializableException。

The DAO class is not Serializable, but it shouldn't have to be. DAO类不是可序列化的,但不一定必须是。 I use @SpringBean to inject the bean (and have dozens of other beans injected with @SpringBean within this large application that all work just fine) 我使用@SpringBean注入bean(在这个大型应用程序中还有数十个其他注入@SpringBean的bean都可以正常工作)

The error doesn't occur until the ajax call completes and the page is serialized. 在ajax调用完成并且页面被序列化之前,不会发生该错误。 Then it fails on each successive request cycle. 然后,它在每个连续的请求周期失败。

I can't see anything special about the DAO class - it has no member variables or does anything special that other DAO classes do. 我看不到DAO类有什么特别的地方-它没有成员变量或其他DAO类没有什么特别的地方。 I can't understand why it works fine in one panel but not in the other. 我不明白为什么它在一个面板中效果很好,但在另一个面板中效果不佳。

I've tried making the member variable transient in the offending panel and using Injector but it doesn't make a difference. 我曾尝试在有问题的面板中使用Injector使成员变量变为瞬态,但这并没有什么不同。

The DAO interface: DAO界面:

public interface StringResourceDAO extends EntityDAO<StringResource, Long> {

  .. other methods
  public List<String> reverseLookup( TranslationType p_type, String p_searchString, Locale p_locale, String p_style, String p_variation ) throws GetException;
}

The DAO class: DAO类:

public class StringResourceJpaDAO extends AbstractEntityJpaDAO<StringResource> implements StringResourceDAO {
  ... other methods

  @Override
  public List<String> reverseLookup( TranslationType p_type, String p_searchString, Locale p_locale, String p_style, String p_variation ) throws GetException {
    ViewCriteria<StringResource> resourceCriteria = new ViewCriteria<>();
    resourceCriteria.addFilter( new EqualityFilter<String>( StringResource_.key, Operator.STARTS_WITH, p_type.getPrefix() ) );
    resourceCriteria.addFilter( EqualityFilter.equalFilter( StringResource_.localeCountry, p_locale == null ? null : StringUtils.defaultIfEmpty( p_locale.getCountry(), null ) ) );
    resourceCriteria.addFilter( EqualityFilter.equalFilter( StringResource_.localeLanguage, p_locale == null ? null : StringUtils.defaultIfEmpty( p_locale.getLanguage(), null ) ) );
    resourceCriteria.addFilter( new EqualityFilter<String>( StringResource_.value, Operator.LIKE, "%" + p_searchString + "%" ).setCaseSensitive( false ) );
    resourceCriteria.setDistinctResults( true );
    resourceCriteria.setMaxResults( 250 );

    List<String> matchingKeys = super.getOtherProperty( l_resourceCriteria, StringResource.class, String.class, StringResource_.key.getName() );
    return new ProxyList<String,String>( l_matchingKeys ) {

      private static final long serialVersionUID = 1L;

      @Override
      public String getItem( String p_proxy ) {
        return TranslationType.removePrefix( p_type, p_proxy );
      }

    };
  }

}

AbstractEntityJpaDAO is a parent class used by all the other DAO implementations. AbstractEntityJpaDAO是所有其他DAO实现使用的父类。 ProxyList is just a pre-stream() wrapper List implementation to allow for access to list properties without having to copy the contents of the list. ProxyList只是pre-stream()包装器List的实现,允许访问列表属性而不必复制列表的内容。 ViewCriteria acts as a bridge between the JPA in the lower layers and the UI logic above for creating data queries. ViewCriteria充当较低层的JPA与上面用于创建数据查询的UI逻辑之间的桥梁。

The component that works fine (a panel not in a ModalWindow): 正常工作的组件(不在ModalWindow中的面板):

public abstract class ServiceLevelLookupPanel extends AbstractDialogPanel {

  @SpringBean
  protected StringResourceDAO m_resourceService;

  protected void onInitialize() {
    TextField<String> serviceLevelNumberField = new TextField<String>( "serviceLevelNumberField", m_serviceLevelNumberModel );
    // HAVE to set this to not required, otherwise the onchange event won't fire if the user empties the text field
    serviceLevelNumberField.setRequired( false );
    serviceLevelNumberField.setConvertEmptyInputStringToNull( true );
    serviceLevelNumberField.add( new AjaxFormComponentUpdatingBehavior("onchange") {

      private static final long serialVersionUID = 1L;

      @Override
      protected void onUpdate( AjaxRequestTarget p_target ) {
        String slNumber = getSearchString();
        // works just fine!
        List<String> translationReverseLookupCodes = m_resourceService.reverseLookup( TranslationType.SERVICE_LEVEL_DESCRIPTION, slNumber, getLocale(), null, null );
      }

    });
  }
}

The component that fails (a panel within a ModalWindow): 发生故障的组件(ModalWindow中的面板):

public class ChooseServiceLevelPanel extends Panel implements IAjaxIndicatorAware {

  @SpringBean
  protected StringResourceDAO m_resourceService;

  protected void onInitialize() {
   ...

    AjaxSubmitLink searchButton = new AjaxSubmitLink( "searchButton" ) {

      private static final long serialVersionUID = 1L;

      @Override
      public void onSubmit( AjaxRequestTarget p_target, Form<?> p_form ) {
        // once this is called, subsequent page serializations fail!
        List<String> matchingServiceLevelCodes = m_resourceService.reverseLookup( TranslationType.SERVICE_LEVEL_DESCRIPTION, m_descriptionModel.getObject(), getLocale(), null, null );
      }
    };
    searchForm.add( l_searchButton );
}

The only differences/things of note that I can see are: 我可以看到的唯一区别/注意事项是:

  • The failing one is in an ajax form submit (the non-failing one doesn't use a form) 失败者以ajax表单提交(非失败者不使用表单)
  • There are 2 forms on the failing page (one to submit the search params, the other to select a search result) 失败页面上有2种形式(一种提交搜索参数,另一种选择搜索结果)
  • The failing one is a panel inside a ModalWindow 失败的是ModalWindow内部的面板

Has anyone had any similar problems? 有没有类似的问题?

Thanks 谢谢

(posting in case anyone had similar issues) (如果有人遇到类似问题,请发布)

The problem was because of the ProxyList - because I created an anonymous implementation of the ProxyList within the DAO class, and this was returned to put in the criteria, it meant that the StringResourceDAO had to be serialized as well. 问题是由于ProxyList所致-因为我在DAO类中创建了ProxyList的匿名实现,并且将其返回到标准中,所以这意味着StringResourceDAO也必须进行序列化。

By replacing the ProxyList with List.stream.filter.collect, it solved the problem. 通过用List.stream.filter.collect替换ProxyList,它解决了这个问题。

(although I still don't understand why it worked for one panel but not the other) (尽管我仍然不明白为什么它适用于一个小组而不适用于另一个小组)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM