RequestFactory: интерфейс реализации прокси с обобщениями

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

java.lang.NullPointerException: null
    at com.google.web.bindery.autobean.vm.impl.MethodPropertyContext.traverse(MethodPropertyContext.java:102) ~[gwt-servlet-2.6.0.jar:na]
    at com.google.web.bindery.autobean.vm.impl.MethodPropertyContext.accept(MethodPropertyContext.java:75) ~[gwt-servlet-2.6.0.jar:na]
    at com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl$PropertyCoderCreator.maybeCreateCoder(AutoBeanCodexImpl.java:353) ~[gwt-servlet-2.6.0.jar:na]
    at com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl$PropertyCoderCreator.visitReferenceProperty(AutoBeanCodexImpl.java:341) ~[gwt-servlet-2.6.0.jar:na]
    at com.google.web.bindery.autobean.vm.impl.ProxyAutoBean.traverseProperties(ProxyAutoBean.java:324) ~[gwt-servlet-2.6.0.jar:na]
    at com.google.web.bindery.autobean.shared.impl.AbstractAutoBean.traverse(AbstractAutoBean.java:166) ~[gwt-servlet-2.6.0.jar:na]
...

Мой прокси класс:

@ProxyFor(value = OutilLibre.class, locator = OutilLibreLocator.class)
public interface OutilLibreProxy extends ProxyWithId, ProxyWithCartoLibre<OutilProxy>, EntityProxy {

    public Long getId();

    public void setId(Long id);

    @Override
    OutilProxy getCompetence();

    @Override
    void setCompetence(OutilProxy outil);

    @Override
    String getCompetenceAutre();

    @Override
    void setCompetenceAutre(String competence);

}

Интерфейс с дженериками:

public interface ProxyWithCartoLibre<T> {

    T getCompetence();

    void setCompetence(T competence);

    String getCompetenceAutre();

    void setCompetenceAutre(String competence);

}   

Соответствующий объект сервера:

@Entity
@Table(name = "outil_libre")
public class OutilLibre extends AEntityLongId implements IBeanCartoLibre<Outil>, IUniqueVersionEntity {

    private static final long serialVersionUID = 45107725880220830L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "outil_libre_seq_gen")
    @SequenceGenerator(name = "outil_libre_seq_gen", sequenceName = "seq_outil_libre")
    @Column(name = "id", unique = true, nullable = false, precision = 5, scale = 0)
    private Long id;

    @Cascade(value = {org.hibernate.annotations.CascadeType.SAVE_UPDATE})
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "outil", nullable = false)
    private Outil outil;

    @Column(name = "outil_autre")
    private String outilAutre;

    @Override
    public Long getId() {
        return id;
    }

    @Override
    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public Outil getCompetence() {
        return outil;
    }

    @Override
    public void setCompetence(Outil outil) {
        this.outil = outil;
    }

    @Override
    public String getCompetenceAutre() {
        return outilAutre;
    }

    @Override
    public void setCompetenceAutre(String competence) {
        this.outilAutre = competence;
    }

}   

Я не знаю, почему я получаю эту ошибку, потому что интерфейс ProxyWithCartoLibre просто используется классами на стороне клиента и не имеет никакой цели в определении фактора запроса.

Есть ли способ сообщить генератору GWT об исключении интерфейса ProxyWithCartoLibre?

Заранее спасибо.

РЕДАКТИРОВАТЬ

java.lang.NullPointerException: null
     at com.google.web.bindery.autobean.vm.impl.MethodPropertyContext.traverse(MethodPropertyContext.java:102) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.autobean.vm.impl.MethodPropertyContext.accept(MethodPropertyContext.java:75) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl$PropertyCoderCreator.maybeCreateCoder(AutoBeanCodexImpl.java:353) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl$PropertyCoderCreator.visitReferenceProperty(AutoBeanCodexImpl.java:341) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.autobean.vm.impl.ProxyAutoBean.traverseProperties(ProxyAutoBean.java:324) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.autobean.shared.impl.AbstractAutoBean.traverse(AbstractAutoBean.java:166) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.autobean.shared.impl.AbstractAutoBean.accept(AbstractAutoBean.java:101) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl.doCoderFor(AutoBeanCodexImpl.java:522) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.autobean.shared.impl.AbstractAutoBean.setProperty(AbstractAutoBean.java:276) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.autobean.vm.impl.ProxyAutoBean.setProperty(ProxyAutoBean.java:253) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.autobean.vm.impl.BeanPropertyContext.set(BeanPropertyContext.java:44) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.requestfactory.server.Resolver$PropertyResolver.visitValueProperty(Resolver.java:211) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.autobean.vm.impl.ProxyAutoBean.traverseProperties(ProxyAutoBean.java:289) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.autobean.shared.impl.AbstractAutoBean.traverse(AbstractAutoBean.java:166) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.autobean.shared.impl.AbstractAutoBean.accept(AbstractAutoBean.java:101) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.requestfactory.server.Resolver.resolveClientValue(Resolver.java:470) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.requestfactory.server.SimpleRequestProcessor.processInvocationMessages(SimpleRequestProcessor.java:491) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.requestfactory.server.SimpleRequestProcessor.process(SimpleRequestProcessor.java:233) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.requestfactory.server.SimpleRequestProcessor.process(SimpleRequestProcessor.java:135) ~[gwt-servlet.jar:na]
     at com.google.web.bindery.requestfactory.server.RequestFactoryServlet.doPost(RequestFactoryServlet.java:133) ~[gwt-servlet.jar:na]
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:647) [servlet-api.jar:na]
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:728) [servlet-api.jar:na]
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) [catalina.jar:7.0.39.B]
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.39.B]
     at ch.qos.logback.access.servlet.TeeFilter.doFilter(TeeFilter.java:55) [logback-access-1.0.13.jar:na]
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [catalina.jar:7.0.39.B]
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.39.B]
     at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:180) [spring-orm-3.2.4.RELEASE.jar:3.2.4.RELEASE]
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [catalina.jar:7.0.39.B]
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.39.B]
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:146) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) [spring-security-web-3.1.4.RELEASE.jar:3.1.4.RELEASE]
     at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
     at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [catalina.jar:7.0.39.B]
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.39.B]
     at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-3.2.2.RELEASE.jar:3.2.2.RELEASE]
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [catalina.jar:7.0.39.B]
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [catalina.jar:7.0.39.B]
     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) [catalina.jar:7.0.39.B]
     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) [catalina.jar:7.0.39.B]
     at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) [catalina.jar:7.0.39.B]
     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) [catalina.jar:7.0.39.B]
     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) [catalina.jar:7.0.39.B]
     at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947) [catalina.jar:7.0.39.B]
     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) [catalina.jar:7.0.39.B]
     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) [catalina.jar:7.0.39.B]
     at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009) [tomcat-coyote.jar:7.0.39.B]
     at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) [tomcat-coyote.jar:7.0.39.B]
     at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) [tomcat-coyote.jar:7.0.39.B]
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_60]
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_60]
     at java.lang.Thread.run(Thread.java:745) [na:1.7.0_60]

1 ответ

Я также получил это исключение, много пытался и придумал следующий обходной путь:

  1. Создайте базовую "базовую" модель bean/POJO для ваших классов, избегая обобщений (во внешнем классе использование обобщений не кажется проблемой) и, возможно, используя некоторые "строки маркеров", такие как _ чтобы помочь избежать (через "оптимистическое" использование интерфейса) более позднего использования "нежелательных классов / методов" или предоставить желаемые варианты, например:

    interface _Person< PERSON extends _Person<PERSON> > extends IsSerializable {  
                       // generics here: just to show that generics work if _Person is not 
                       // referenced itself in AutoBean (de)serialization
      int getId();
      void setId( int id );     // normally we may not want to expose this, but for the
                                // (de)serialization it is/may be necessary or benefitial 
                                // here now
      String getName();
      void setName( String name );
      //_Person setName_( String name );
                            // to have fluent setters is against Bean definition and does 
                            // not work with AutoBeans, but since there is no getter
                            // "getName()" it is ignored and would work :-)
                            // (but it may be better to not include it in here)
      _Address getAddr_();
      void setAddr_( _Address addr );
    }
    
    //interface _Address< ADDR extends _Address > extends IsSerializable {
      // => would e.g. cause the NullPointerException ! :-(
      //    at com.google.web.bindery.autobean.vm.impl.MethodPropertyContext.traverse(
      //         MethodPropertyContext.java:102) ~[gwt-user-2.6.0.jar:na]
    interface _Address extends IsSerializable {
       String getCity_();
       void setCity_( String city );
    }
    
    • теперь использование этого с функциональностью AutoBean будет работать на них, и если кто-то использует общие интерфейсы и реализации вокруг них позже, должно работать (я попробовал только простой пример, подобный этому, чтобы проверить это для меня). Пример с вышеупомянутым должен работать (неполный фрагмент): AutoBeanCodex.encode( personAutoBean ).deepCopy()
  2. Теперь создание общих интерфейсов и классов, наследуемых от них, имеет недостаток, например, невозможность

    • вернуть общий person.getAddr_().getNonBeanFooExtension() или же
    • использовать свободный интерфейс, такой как person.setName_( "foo" ).setMail( "bar" ) или же
    • предотвращение / препятствование доступу к person.setId( 123 )

    Поэтому я планирую сейчас (я сообщу, когда это будет сделано), тем не менее, извлекать уроки из этих ранее, но также писать "не связанные между собой наследования" / перекрывающиеся интерфейсы, которые / должны "нормально" использоваться в бизнес-приложении, например:

    interface Person< PERSON extends Person<PERSON>> {
       // extends _Person <= no, because then we could not "hide/discourage" users calling 
       // e.g. "setId(....)"
      int getId();
    
      String getName();
      //void setName( String name );  // we could provide it, but setName_() does the same
                                      // and more and only one setter keeps the interface 
                                      // smaller
      PERSON setName_( String name );
      Address<PERSON> getAddr();
      PERSON setAddr( Address<PERSON> addr );
    
      PERSON setFancyThing();          // not "seen" by AutoBean and thus should not 
                                       // cause trouble there
    }
    
    interface Address< PERSON extends Person<PERSON> > {
      ...
    }
    
  3. теперь реализации классов, как это должно работать в целом (пока только проверенный простой случай):

    class PersonDTO implements Person<PersonDTO>, _Person<PersonDTO> {
      ...
    }
    
  4. "пользователи" этих реализаций должны как можно больше работать с интерфейсами из 2. Person<PersonDto> pers = ... поэтому они видят довольно приятный интерфейс и не могут легко вызвать pers.setId( 123 ) , но pers.setName_( "Dimitri Khalezov" ).setMail_( ... )

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

Другие вопросы по тегам