代码之家  ›  专栏  ›  技术社区  ›  Chris Hinshaw

GWT RequestFactory在错误的对象上调用setter

  •  0
  • Chris Hinshaw  · 技术社区  · 10 年前

    首先,它不是错误的对象,但它不是正确的参考,因为我已经诊断出了问题。

    我有一个编辑器,我正在编辑一个包含更多bean的另一个列表编辑器的对象。

    我有一个TagCollectionProxy,其中包含一个TagProxy对象列表。在保存带有附加列表对象的TagCollectionProxy时出现问题。我的实体定位器正在数据库中查找对象并设置值,但我没有对该对象的引用。这是新的,我不知道为什么现在会这样。

    当我在对象上调用save时,出现此调试消息。我在setValue的Tag类中放置了一条消息,您可以看到我在域实体上设置了正确的值。id匹配。问题出现在dao类中保存(TagCollection)的下一条消息中。我正在遍历实体并打印值,但该实体的值没有更改。

    2014-08-29T15:34:15.912-0500|INFO: Setting value Tag2asdfasdfasdfasdf for id 294 Reference cpbx.rialto.dms.Tag@1135696
    2014-08-29T15:34:15.944-0500|INFO: Tag name => asdfasdf Tag value => Tag2 id => 294 ref => cpbx.rialto.dms.Tag@1893889
    2014-08-29T15:34:15.944-0500|INFO: Id of tag is 294
    

    提前感谢你的帮助,我现在正在脱发。

    这是保存对象的“活动”。请注意,我正在保存包含标记列表的TagCollectionProxy。

    public class TagCollectionEditActivity extends AbstractActivity<TagCollectionEditView> implements
            TagCollectionEditView.Presenter {
    
    
    
        private Receiver<Long> saveReceiver = new Receiver<Long>() {
            @Override
            public void onSuccess(Long response) {
                logger.info("saved tagCollection with id of " + response);
                clientFactory.getPlaceController().goTo(new TagCollectionsPlace());
            }
    
            public void onConstraintViolation(Set<ConstraintViolation<?>> violations) {
    
                for (ConstraintViolation<?> violation : violations) {
                    logger.warning(violation.getMessage());
                }
                getDisplay().getEditorDriver().setConstraintViolations(violations);
            }
    
            public void onFailure(ServerFailure failure) {
                logger.log(Level.SEVERE, "Failed to save tag collection " + failure.getMessage());
                getDisplay().showError(failure);
            }
        };
    
        private static final Logger logger = Logger.getLogger(TagCollectionEditActivity.class.getName());
    
        private IClientFactory clientFactory;
    
        private TagCollectionDaoRequest editContext = null;
    
        public TagCollectionEditActivity(IClientFactory clientFactory) {
            super(new TagCollectionEditView(clientFactory.getResources(), clientFactory.getEventBus()));
            this.clientFactory = clientFactory;
        }
    
        @Override
        protected void bindToView() {
            getDisplay().setPresenter(this);
            final TagCollectionEditPlace place = (TagCollectionEditPlace) getPlace();
            Long tagCollectionId = place.getTagCollectionId();
    
            if (tagCollectionId == null) {
                createTagCollection();
            } else {
                findCollection(tagCollectionId);
            }
        }
    
        private void findCollection(Long tagCollectionId) {
            clientFactory.tagCollectionRequest().find(tagCollectionId).with(getEntityProperties())
                    .fire(new Receiver<TagCollectionProxy>() {
    
                        @Override
                        public void onSuccess(TagCollectionProxy tagCollection) {
                            editContext = clientFactory.tagCollectionRequest();
                            editContext.save(tagCollection).with(getDisplay().getEditorDriver().getPaths()).to(saveReceiver);
                            getDisplay().getEditorDriver().edit(tagCollection, editContext);
                            GWT.log("Context is " + editContext.hashCode());
                        }
                    });
        }
    
        private void createTagCollection() {
            editContext = clientFactory.tagCollectionRequest();
            TagCollectionProxy tagCollection = editContext.create(TagCollectionProxy.class);
            editContext.save(tagCollection).with(getDisplay().getEditorDriver().getPaths()).to(saveReceiver);
            tagCollection.setTags(new ArrayList<TagProxy>());
            getDisplay().getEditorDriver().edit(tagCollection, editContext);
        }
    
        @Override
        public void onSave() {
            RequestContext context = getDisplay().getEditorDriver().flush();
            context.fire();
        }   
    
        public String[] getEntityProperties() {
            return new String[] { "tags", "deviceFamily" };
        }
    
        @Override
        public void onCancel() {
            clientFactory.getPlaceController().goTo(new TagCollectionsPlace());
        }
    }
    

    这是我的标记集合代理,我在其中定义了DomainEntityLocator

    @ProxyFor(value = TagCollection.class, locator = DomainEntityLocator.class)
    public interface TagCollectionProxy extends DomainEntityProxy {
    
        public List<TagProxy> getTags();
    
        public void setTags(List<TagProxy> tags);
    
        public DeviceFamilyProxy getDeviceFamily();
    
        public void setDeviceFamily(DeviceFamilyProxy deviceFamily);
    
    }
    

    这是我的定位器,它使用JPA实体管理器使用数据库查找对象。

    public class DomainEntityLocator extends Locator<DomainEntity, Long> {
    
        private static EntityManager em = null;
    
        static {
            Context initCtx;
            try {
                initCtx = new InitialContext();
                // perform JNDI lookup to obtain container-managed entity manager
                em = (javax.persistence.EntityManager) initCtx.lookup("java:comp/env/persistence/DomainEntityManager");
    
            } catch (NamingException e) {
                throw new RuntimeException("Unable to get the domain entity manager");
            }
        }
    
        public DomainEntityLocator() {
        }
    
        @Override
        public DomainEntity create(Class<? extends DomainEntity> clazz) {
            try {
                return clazz.newInstance();
            } catch (InstantiationException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    
        @Override
        public DomainEntity find(Class<? extends DomainEntity> clazz, Long id) {
            return em.find(clazz, id);
        }
    
        @Override
        public Class<DomainEntity> getDomainType() {
            return DomainEntity.class;
        }
    
        @Override
        public Long getId(DomainEntity domainObject) {
            return domainObject.getId();
        }
    
        @Override
        public Class<Long> getIdType() {
            return Long.class;
        }
    
        @Override
        public Object getVersion(DomainEntity domainObject) {
            return 0;
        }
    }
    

    使现代化

    经过一番调查,我意识到服务器端的JPA应该为我的问题负责。我得出的结论是,DomainEntityLocator正在获取实体,但没有将其包装在事务中。因此,DomainEntityLocator#find()方法将检索实体,ServiceLayer将修改实体上的值。我遇到的问题是find方法没有包装在事务中,并且由于我检索的实体管理器没有被管理,所以实体管理器不会刷新更改。因此,我没有看到值的更新。

    关于主题问题#2

    是否有将事务管理添加到实体定位器的常见模式,以便在请求工厂调用setter后持久化对象。我以前用一个简单的servlet过滤器来实现这一点,但我正在进行的项目需要javaee来维护这种功能。由于ServiceLayer查找的方式,我无法将DomainEntityLocator设置为无状态bean。最好扩展RequestFactoryServlet并将doPost包装在一个transasction中吗?这似乎是最合乎逻辑的想法。有什么建议吗?

    再次感谢Thomas

    2 回复  |  直到 10 年前
        1
  •  2
  •   Thomas Broyer    10 年前

    在服务器端,RequestFactory将使用定位器按其ID加载每个对象,因此 TagCollection 将加载(及其列表 Tag )和每个 标签 也将使用 DomainEntityLocator (假设这就是他们在 @ProxyFor ).
    setter将在定位器返回的对象上调用,而不是来自 标记集合 getTags 列表

    你必须确保它们是相同的实例。

    对于JPA,这意味着使用“视图中的开放会话”(也称为“每个请求的会话”)模式。JPA会话使用缓存,因此在整个HTTP请求中共享相同的会话将确保 标签 无论何时从 标记集合 或直接通过他们的ID。

        2
  •  0
  •   Chris Hinshaw    10 年前

    以下是我使用EJB和RequestFactory解决问题的方法。

    在发现RequestFactory方法没有被包装在实体管理器的事务中之后,我想到了两个选择。一个是我可以在实体定位器的查找和创建方法中添加一个UserTransaction,但我决定将整个请求包装在一个事务中,这对我的情况很好,因为我的请求工厂方法应该总是在事务中。

    我扩展了requestfactoryServlet并向doPost添加了UserTransaction。

    @WebServlet("/rf/secure/dao")
    public class DmsRequestFactoryServlet extends RequestFactoryServlet {
    
        private static final long serialVersionUID = -521670028586842819L;
    
        private static final Logger logger = Logger.getLogger(DmsRequestFactoryServlet.class.getName());
    
        @Resource
        private UserTransaction tx;
    
    
        public static class SimpleExceptionHandler implements ExceptionHandler {
    
            @Override
            public ServerFailure createServerFailure(Throwable throwable) {
                logger.log(Level.SEVERE, "Unable to complete request", throwable);
    
                return new ServerFailure("Server Error: " + (throwable == null ? null : throwable.getMessage()), throwable
                        .getClass().getName(), ExceptionUtils.getStackTrace(throwable), true);
            }
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException,
                ServletException {
            try {
                tx.begin();
                super.doPost(request, response);
                tx.commit();
            } catch (Exception e) {
                logger.log(Level.SEVERE, "Failed request ", e);
            }
        }
    
        public DmsRequestFactoryServlet() {
            super(new SimpleExceptionHandler());
        }
    }