com.google.web.bindery.requestfactory.shared.impl.ProxySerializerImpl Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.web.bindery.requestfactory.shared.impl;
import com.google.web.bindery.autobean.shared.AutoBean;
import com.google.web.bindery.autobean.shared.AutoBeanCodex;
import com.google.web.bindery.autobean.shared.AutoBeanFactory;
import com.google.web.bindery.autobean.shared.AutoBeanUtils;
import com.google.web.bindery.autobean.shared.AutoBeanVisitor;
import com.google.web.bindery.autobean.shared.Splittable;
import com.google.web.bindery.requestfactory.shared.BaseProxy;
import com.google.web.bindery.requestfactory.shared.EntityProxy;
import com.google.web.bindery.requestfactory.shared.EntityProxyId;
import com.google.web.bindery.requestfactory.shared.ProxySerializer;
import com.google.web.bindery.requestfactory.shared.ProxyStore;
import com.google.web.bindery.requestfactory.shared.messages.IdMessage;
import com.google.web.bindery.requestfactory.shared.messages.IdMessage.Strength;
import com.google.web.bindery.requestfactory.shared.messages.OperationMessage;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* The default implementation of ProxySerializer.
*/
class ProxySerializerImpl extends AbstractRequestContext implements ProxySerializer {
/**
* Used internally to unwind the stack if data cannot be found in the backing
* store.
*/
private static class NoDataException extends RuntimeException {
}
private final ProxyStore store;
/**
* If the user wants to serialize a proxy with a non-persistent id (including
* ValueProxy), we'll assign a synthetic id that is local to the store being
* used.
*/
private final Map, SimpleProxyId> syntheticIds =
new HashMap, SimpleProxyId>();
/**
* The ids of proxies whose content has been reloaded.
*/
private final Set> restored = new HashSet>();
private final Map, AutoBean> serialized =
new HashMap, AutoBean>();
public ProxySerializerImpl(AbstractRequestFactory factory, ProxyStore store) {
super(factory, Dialect.STANDARD);
this.store = store;
}
public T deserialize(Class proxyType, String key) {
// Fast exit to prevent getOperation from throwing an exception
if (store.get(key) == null) {
return null;
}
OperationMessage op = getOperation(key);
@SuppressWarnings("unchecked")
SimpleProxyId id = (SimpleProxyId) getId(op);
return doDeserialize(id);
}
public T deserialize(EntityProxyId id) {
return doDeserialize((SimpleEntityProxyId) id);
}
/**
* Replace non-persistent ids with store-local ids.
*/
@Override
public Splittable getSerializedProxyId(SimpleProxyId stableId) {
return super.getSerializedProxyId(serializedId(stableId));
}
public String serialize(BaseProxy rootObject) {
if (rootObject == null) {
return "null";
}
final AutoBean root = AutoBeanUtils.getAutoBean(rootObject);
if (root == null) {
// Unexpected, some kind of foreign implementation of the BaseProxy?
throw new IllegalArgumentException();
}
final SimpleProxyId id = serializedId(BaseProxyCategory.stableId(root));
// Only persistent and synthetic ids expected
assert !id.isEphemeral() : "Unexpected ephemeral id " + id.toString();
/*
* Don't repeatedly serialize the same proxy, unless we're looking at a
* mutable instance.
*/
AutoBean previous = serialized.get(id);
if (previous == null || !previous.isFrozen()) {
serialized.put(id, root);
serializeOneProxy(id, root);
root.accept(new AutoBeanVisitor() {
@Override
public void endVisit(AutoBean bean, Context ctx) {
// Avoid unnecessary method call
if (bean == root) {
return;
}
if (isEntityType(bean.getType()) || isValueType(bean.getType())) {
serialize((BaseProxy) bean.as());
}
}
@Override
public void endVisitCollectionProperty(String propertyName, AutoBean> value,
CollectionPropertyContext ctx) {
if (value == null) {
return;
}
if (isEntityType(ctx.getElementType()) || isValueType(ctx.getElementType())) {
for (Object o : value.as()) {
serialize((BaseProxy) o);
}
}
}
@Override
public void endVisitMapProperty(String propertyName, AutoBean