拳頭它不是錯誤的對象,但它不是正確的參考,因爲我診斷出這個問題。GWT RequestFactory調用設置錯誤的對象
我有一個編輯器,我正在編輯一個包含更多bean的另一個列表編輯器的對象。
我有一個TagCollectionProxy,它包含一個TagProxy對象列表。當我使用附加的List對象保存TagCollectionProxy時,就會出現問題。我的實體定位器正在查找數據庫中的對象並設置該值,但是我沒有對該對象的引用。這是新的,我不知道爲什麼現在發生這種情況。
當我調用保存在對象上的調試消息。我在setValue的Tag類中放了一條消息,你可以看到我在域實體上設置了正確的值。 id匹配。問題出現在我的dao類中保存(TagCollection)的下一條消息中。我正在遍歷實體並打印該值,但該實體的值未變。
2014-08-29T15:34:15.912-0500|INFO: Setting value Tag2asdfasdfasdfasdf for id 294 Reference [email protected]
2014-08-29T15:34:15.944-0500|INFO: Tag name => asdfasdf Tag value => Tag2 id => 294 ref => [email protected]
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的EntityManager對象。
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過濾器來做到這一點,但是我正在處理的項目需要java ee來維護這種功能。我無法使DomainEntityLocator成爲無狀態bean,因爲ServiceLayer會查找它。最好是擴展RequestFactoryServlet並將doPost包裝在tranasction中?這似乎是最合乎邏輯的想法。有什麼建議麼?
再次感謝托馬斯
托馬斯,謝謝你的幫助。經過一些調試,我得出了和你一樣的結論。我最初的困惑源自Chrome,並未在(調試工具)預覽面板中打印整個發佈消息。我不得不深入Header面板才能看到整個傳出的消息。我用一個小小的更新更新了這個問題。如果你知道一個很好的解決方案來包裝定位器,如果這是一個好主意,請告訴我。 – 2014-09-02 14:30:42
在交易中包裝整個請求/響應會引發麻煩:如果您這樣做,RF語義將會改變。你需要的是「open session in view」模式(每個請求/響應一個'EntityManager'),然後將你的事務範圍擴展到你的服務方法。 – 2014-09-03 08:51:54