package io.ebeaninternal.server.text.json;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.text.json.JsonReadBeanVisitor;
import io.ebean.text.json.JsonReadOptions;
import io.ebeaninternal.api.LoadContext;
import io.ebeaninternal.api.json.SpiJsonReader;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.loadcontext.DLoadContext;
import io.ebeaninternal.server.transaction.DefaultPersistenceContext;
import java.io.IOException;
import java.util.Map;
public class ReadJson implements SpiJsonReader {
private final BeanDescriptor<?> rootDesc;
private final JsonParser parser;
private final PathStack pathStack;
private final Map<String, JsonReadBeanVisitor<?>> visitorMap;
private final Object objectMapper;
private final PersistenceContext persistenceContext;
private final LoadContext loadContext;
public ReadJson(BeanDescriptor<?> desc, JsonParser parser, JsonReadOptions readOptions, Object objectMapper) {
this.rootDesc = desc;
this.parser = parser;
this.objectMapper = objectMapper;
this.persistenceContext = initPersistenceContext(readOptions);
this.loadContext = initLoadContext(desc, readOptions);
this.visitorMap = (readOptions == null) ? null : readOptions.getVisitorMap();
this.pathStack = (visitorMap == null && loadContext == null) ? null : new PathStack();
}
private ReadJson(JsonParser moreJson, ReadJson source, boolean resetContext) {
this.parser = moreJson;
this.rootDesc = source.rootDesc;
this.pathStack = source.pathStack;
this.visitorMap = source.visitorMap;
this.objectMapper = source.objectMapper;
if (resetContext) {
this.persistenceContext = new DefaultPersistenceContext();
this.loadContext = source.loadContext;
if (loadContext != null) {
loadContext.resetPersistenceContext(persistenceContext);
}
} else {
this.persistenceContext = source.persistenceContext;
this.loadContext = source.loadContext;
}
}
private LoadContext initLoadContext(BeanDescriptor<?> desc, JsonReadOptions readOptions) {
if (readOptions == null) return null;
if (readOptions.isEnableLazyLoading() && readOptions.getLoadContext() == null) {
return new DLoadContext(desc, persistenceContext);
} else {
return (LoadContext) readOptions.getLoadContext();
}
}
private PersistenceContext initPersistenceContext(JsonReadOptions readOptions) {
if (readOptions != null && readOptions.getPersistenceContext() != null) {
return readOptions.getPersistenceContext();
}
return new DefaultPersistenceContext();
}
@Override
public PersistenceContext getPersistenceContext() {
return persistenceContext;
}
@Override
public SpiJsonReader forJson(JsonParser moreJson, boolean resetContext) {
return new ReadJson(moreJson, this, resetContext);
}
@Override
public <T> void persistenceContextPut(Object beanId, T currentBean) {
persistenceContextPutIfAbsent(beanId, (EntityBean) currentBean, rootDesc);
}
@Override
public Object persistenceContextPutIfAbsent(Object id, EntityBean bean, BeanDescriptor<?> beanDesc) {
if (persistenceContext == null) {
return null;
}
Object existing = beanDesc.contextPutIfAbsent(persistenceContext, id, bean);
if (existing != null) {
beanDesc.merge(bean, (EntityBean) existing);
} else {
if (loadContext != null) {
EntityBeanIntercept ebi = bean._ebean_getIntercept();
if (ebi.isPartial()) {
String path = pathStack.peekWithNull();
loadContext.register(path, ebi);
beanDesc.lazyLoadRegister(path, ebi, bean, loadContext);
}
ebi.setLoaded();
}
return null;
}
return existing;
}
@Override
public ObjectMapper getObjectMapper() {
if (objectMapper == null) {
throw new IllegalStateException(
"Jackson ObjectMapper required but has not set. The ObjectMapper can be set on"
+ " either the DatabaseConfig or on JsonReadOptions.");
}
return (ObjectMapper) objectMapper;
}
@Override
public JsonParser getParser() {
return parser;
}
@Override
public JsonToken nextToken() throws IOException {
return parser.nextToken();
}
@Override
public void pushPath(String path) {
if (pathStack != null) {
pathStack.pushPathKey(path);
}
}
@Override
public void popPath() {
if (pathStack != null) {
pathStack.pop();
}
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public void beanVisitor(Object bean, Map<String, Object> unmappedProperties) {
if (visitorMap != null) {
JsonReadBeanVisitor visitor = visitorMap.get(pathStack.peekWithNull());
if (visitor != null) {
visitor.visit(bean, unmappedProperties);
}
}
}
@Override
public Object readValueUsingObjectMapper(Class<?> propertyType) throws IOException {
return getObjectMapper().readValue(parser, propertyType);
}
}