Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne Maven / Gradle / Ivy
/**
* Copyright (C) 2006 Robin Bygrave
*
* This file is part of Ebean.
*
* Ebean is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* Ebean is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Ebean; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.InvalidValue;
import com.avaje.ebean.Query;
import com.avaje.ebean.SqlUpdate;
import com.avaje.ebean.Transaction;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
import com.avaje.ebeaninternal.server.core.ReferenceOptions;
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.query.SplitName;
import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
import com.avaje.ebeaninternal.server.text.json.ReadJsonContext;
import com.avaje.ebeaninternal.server.text.json.WriteJsonContext;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Property mapped to a joined bean.
*/
public class BeanPropertyAssocOne extends BeanPropertyAssoc {
private final boolean oneToOne;
private final boolean oneToOneExported;
private final boolean embeddedVersion;
private final boolean importedPrimaryKey;
private final LocalHelp localHelp;
private final BeanProperty[] embeddedProps;
private final HashMap embeddedPropsMap;
/**
* The information for Imported foreign Keys.
*/
private ImportedId importedId;
private ExportedProperty[] exportedProperties;
private String deleteByParentIdSql;
private String deleteByParentIdInSql;
/**
* Create based on deploy information of an EmbeddedId.
*/
public BeanPropertyAssocOne(BeanDescriptorMap owner, DeployBeanPropertyAssocOne deploy) {
this(owner, null, deploy);
}
/**
* Create the property.
*/
public BeanPropertyAssocOne(BeanDescriptorMap owner, BeanDescriptor> descriptor,
DeployBeanPropertyAssocOne deploy) {
super(owner, descriptor, deploy);
importedPrimaryKey = deploy.isImportedPrimaryKey();
oneToOne = deploy.isOneToOne();
oneToOneExported = deploy.isOneToOneExported();
if (embedded) {
// Overriding of the columns and use table alias of owning BeanDescriptor
BeanEmbeddedMeta overrideMeta = BeanEmbeddedMetaFactory.create(owner, deploy, descriptor);
embeddedProps = overrideMeta.getProperties();
if (id) {
embeddedVersion = false;
} else {
embeddedVersion = overrideMeta.isEmbeddedVersion();
}
embeddedPropsMap = new HashMap();
for (int i = 0; i < embeddedProps.length; i++) {
embeddedPropsMap.put(embeddedProps[i].getName(), embeddedProps[i]);
}
} else {
embeddedProps = null;
embeddedPropsMap = null;
embeddedVersion = false;
}
localHelp = createHelp(embedded, oneToOneExported);
}
@Override
public void initialise() {
super.initialise();
if (!isTransient) {
if (embedded) {
// no imported or exported information
} else if (!oneToOneExported) {
importedId = createImportedId(this, targetDescriptor, tableJoin);
} else {
exportedProperties = createExported();
String delStmt = "delete from "+targetDescriptor.getBaseTable()+" where ";
deleteByParentIdSql = delStmt + deriveWhereParentIdSql(false);
deleteByParentIdInSql = delStmt + deriveWhereParentIdSql(true);
}
}
}
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
if (embedded){
BeanProperty embProp = embeddedPropsMap.get(remainder);
if (embProp == null){
String msg = "Embedded Property "+remainder+" not found in "+getFullBeanName();
throw new PersistenceException(msg);
}
if (chain == null) {
chain = new ElPropertyChainBuilder(true, propName);
}
chain.add(this);
return chain.add(embProp).build();
}
return createElPropertyValue(propName, remainder, chain, propertyDeploy);
}
@Override
public void copyProperty(Object sourceBean, Object destBean, CopyContext ctx, int maxDepth){
localHelp.copyProperty(sourceBean, destBean, ctx, maxDepth);
}
public SqlUpdate deleteByParentId(Object parentId, List parentIdist) {
if (parentId != null){
return deleteByParentId(parentId);
} else {
return deleteByParentIdList(parentIdist);
}
}
private SqlUpdate deleteByParentIdList(List parentIdist) {
StringBuilder sb = new StringBuilder(100);
sb.append(deleteByParentIdInSql);
String inClause = targetIdBinder.getIdInValueExpr(parentIdist.size());
sb.append(inClause);
DefaultSqlUpdate delete = new DefaultSqlUpdate(sb.toString());
for (int i = 0; i < parentIdist.size(); i++) {
targetIdBinder.bindId(delete, parentIdist.get(i));
}
return delete;
}
private SqlUpdate deleteByParentId(Object parentId) {
DefaultSqlUpdate delete = new DefaultSqlUpdate(deleteByParentIdSql);
if (exportedProperties.length == 1){
delete.addParameter(parentId);
} else {
targetDescriptor.getIdBinder().bindId(delete, parentId);
}
return delete;
}
public List findIdsByParentId(Object parentId, List parentIdist, Transaction t) {
if (parentId != null){
return findIdsByParentId(parentId, t);
} else {
return findIdsByParentIdList(parentIdist, t);
}
}
private List findIdsByParentId(Object parentId, Transaction t) {
String rawWhere = deriveWhereParentIdSql(false);
EbeanServer server = getBeanDescriptor().getEbeanServer();
Query> q = server.find(getPropertyType())
.where().raw(rawWhere).query();
bindWhereParendId(q, parentId);
return server.findIds(q, t);
}
private List findIdsByParentIdList(List parentIdist, Transaction t) {
String rawWhere = deriveWhereParentIdSql(true);
String inClause = targetIdBinder.getIdInValueExpr(parentIdist.size());
String expr = rawWhere+inClause;
EbeanServer server = getBeanDescriptor().getEbeanServer();
Query> q = (Query>)server.find(getPropertyType())
.where().raw(expr);
for (int i = 0; i < parentIdist.size(); i++) {
bindWhereParendId(q, parentIdist.get(i));
}
return server.findIds(q, t);
}
private void bindWhereParendId(Query> q, Object parentId) {
if (exportedProperties.length == 1) {
q.setParameter(1, parentId);
} else {
int pos = 1;
for (int i = 0; i < exportedProperties.length; i++) {
Object embVal = exportedProperties[i].getValue(parentId);
q.setParameter(pos++, embVal);
}
}
}
public void addFkey() {
if (importedId != null) {
importedId.addFkeys(name);
}
}
@Override
public boolean isValueLoaded(Object value) {
if (value instanceof EntityBean) {
return ((EntityBean) value)._ebean_getIntercept().isLoaded();
}
return true;
}
@Override
public InvalidValue validateCascade(Object value) {
BeanDescriptor> target = getTargetDescriptor();
return target.validate(true, value);
}
private boolean hasChangedEmbedded(Object bean, Object oldValues) {
Object embValue = getValue(oldValues);
if (embValue instanceof EntityBean) {
// the embedded bean .. has its own old values
return ((EntityBean) embValue)._ebean_getIntercept().isNewOrDirty();
}
if (embValue == null) {
return getValue(bean) != null;
} else {
return false;
}
}
@Override
public boolean hasChanged(Object bean, Object oldValues) {
if (embedded) {
return hasChangedEmbedded(bean, oldValues);
}
Object value = getValue(bean);
Object oldVal = getValue(oldValues);
if (oneToOneExported) {
// FKey on other side
return false;
} else {
if (value == null) {
return oldVal != null;
} else if (oldValues == null) {
return true;
}
return importedId.hasChanged(value, oldVal);
}
}
/**
* Return meta data for the deployment of the embedded bean specific to this
* property.
*/
public BeanProperty[] getProperties() {
return embeddedProps;
}
public void buildSelectExpressionChain(String prefix, List selectChain) {
prefix = SplitName.add(prefix, name);
if (!embedded){
targetIdBinder.buildSelectExpressionChain(prefix, selectChain);
} else {
for (int i = 0; i < embeddedProps.length; i++) {
embeddedProps[i].buildSelectExpressionChain(prefix, selectChain);
}
}
}
/**
* Return true if this a OneToOne property. Otherwise assumed ManyToOne.
*/
public boolean isOneToOne() {
return oneToOne;
}
/**
* Return true if this is the exported side of a OneToOne.
*/
public boolean isOneToOneExported() {
return oneToOneExported;
}
/**
* Returns true if the associated bean has version properties.
*/
public boolean isEmbeddedVersion() {
return embeddedVersion;
}
/**
* If true this bean maps to the primary key.
*/
public boolean isImportedPrimaryKey() {
return importedPrimaryKey;
}
/**
* Same as getPropertyType(). Return the type of the bean this property
* represents.
*/
public Class> getTargetType() {
return getPropertyType();
}
/**
* Return the Id values from the given bean.
*/
@Override
public Object[] getAssocOneIdValues(Object bean) {
return targetDescriptor.getIdBinder().getIdValues(bean);
}
/**
* Return the Id expression to add to where clause etc.
*/
public String getAssocOneIdExpr(String prefix, String operator) {
return targetDescriptor.getIdBinder().getAssocOneIdExpr(prefix, operator);
}
/**
* Return the logical id value expression taking into account embedded id's.
*/
@Override
public String getAssocIdInValueExpr(int size){
return targetDescriptor.getIdBinder().getIdInValueExpr(size);
}
/**
* Return the logical id in expression taking into account embedded id's.
*/
@Override
public String getAssocIdInExpr(String prefix){
return targetDescriptor.getIdBinder().getAssocIdInExpr(prefix);
}
@Override
public boolean isAssocId() {
return !embedded;
}
@Override
public boolean isAssocProperty() {
return !embedded;
}
/**
* Create a vanilla bean of the target type to be used as an embeddedId
* value.
*/
public Object createEmbeddedId() {
return getTargetDescriptor().createVanillaBean();
}
/**
* Return an empty reference object.
*/
public Object createEmptyReference() {
return targetDescriptor.createEntityBean();
}
public void elSetReference(Object bean) {
Object value = getValueIntercept(bean);
if (value != null) {
((EntityBean) value)._ebean_getIntercept().setReference();
}
}
@Override
public Object elGetReference(Object bean) {
Object value = getValueIntercept(bean);
if (value == null) {
value = targetDescriptor.createEntityBean();
setValueIntercept(bean, value);
}
return value;
}
public ImportedId getImportedId() {
return importedId;
}
private String deriveWhereParentIdSql(boolean inClause) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < exportedProperties.length; i++) {
String fkColumn = exportedProperties[i].getForeignDbColumn();
if (i > 0){
String s = inClause ? "," : " and ";
sb.append(s);
}
sb.append(fkColumn);
if (!inClause){
sb.append("=? ");
}
}
return sb.toString();
}
/**
* Create the array of ExportedProperty used to build reference objects.
*/
private ExportedProperty[] createExported() {
BeanProperty[] uids = descriptor.propertiesId();
ArrayList list = new ArrayList();
if (uids.length == 1 && uids[0].isEmbedded()) {
BeanPropertyAssocOne> one = (BeanPropertyAssocOne>) uids[0];
BeanDescriptor> targetDesc = one.getTargetDescriptor();
BeanProperty[] emIds = targetDesc.propertiesBaseScalar();
try {
for (int i = 0; i < emIds.length; i++) {
ExportedProperty expProp = findMatch(true, emIds[i]);
list.add(expProp);
}
} catch (PersistenceException e){
// not found as individual scalar properties
e.printStackTrace();
}
} else {
for (int i = 0; i < uids.length; i++) {
ExportedProperty expProp = findMatch(false, uids[i]);
list.add(expProp);
}
}
return (ExportedProperty[]) list.toArray(new ExportedProperty[list.size()]);
}
/**
* Find the matching foreignDbColumn for a given local property.
*/
private ExportedProperty findMatch(boolean embeddedProp,BeanProperty prop) {
String matchColumn = prop.getDbColumn();
String searchTable = tableJoin.getTable();
TableJoinColumn[] columns = tableJoin.columns();
for (int i = 0; i < columns.length; i++) {
String matchTo = columns[i].getLocalDbColumn();
if (matchColumn.equalsIgnoreCase(matchTo)) {
String foreignCol = columns[i].getForeignDbColumn();
return new ExportedProperty(embeddedProp, foreignCol, prop);
}
}
String msg = "Error with the Join on ["+getFullBeanName()
+"]. Could not find the matching foreign key for ["+matchColumn+"] in table["+searchTable+"]?"
+" Perhaps using a @JoinColumn with the name/referencedColumnName attributes swapped?";
throw new PersistenceException(msg);
}
@Override
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
if (!isTransient) {
localHelp.appendSelect(ctx, subQuery);
}
}
@Override
public void appendFrom(DbSqlContext ctx, boolean forceOuterJoin) {
if (!isTransient) {
localHelp.appendFrom(ctx, forceOuterJoin);
}
}
@Override
public Object readSet(DbReadContext ctx, Object bean, Class> type) throws SQLException {
boolean assignable = (type == null || owningType.isAssignableFrom(type));
return localHelp.readSet(ctx, bean, assignable);
}
/**
* Read the data from the resultSet effectively ignoring it and returning null.
*/
@Override
public Object read(DbReadContext ctx) throws SQLException {
// just read the resultSet incrementing the column index
// pass in null for the bean so any data read is ignored
return localHelp.read(ctx);
}
@Override
public void loadIgnore(DbReadContext ctx) {
localHelp.loadIgnore(ctx);
}
@Override
public void load(SqlBeanLoad sqlBeanLoad) throws SQLException {
sqlBeanLoad.load(this);
}
private LocalHelp createHelp(boolean embedded, boolean oneToOneExported) {
if (embedded) {
return new Embedded();
} else if (oneToOneExported) {
return new ReferenceExported();
} else {
return new Reference(this);
}
}
/**
* Local interface to handle Embedded, Reference and Reference Exported
* cases.
*/
private abstract class LocalHelp {
abstract void copyProperty(Object sourceBean, Object destBean, CopyContext ctx, int maxDepth);
abstract void loadIgnore(DbReadContext ctx);
abstract Object read(DbReadContext ctx) throws SQLException;
abstract Object readSet(DbReadContext ctx, Object bean, boolean assignAble) throws SQLException;
abstract void appendSelect(DbSqlContext ctx, boolean subQuery);
abstract void appendFrom(DbSqlContext ctx, boolean forceOuterJoin);
void copy(Object sourceBean, Object destBean, CopyContext ctx, int maxDepth){
Object value = getValue(sourceBean);
if (value != null){
Class> valueClass = value.getClass();
BeanDescriptor> refDesc = descriptor.getBeanDescriptor(valueClass);
Object refId = refDesc.getId(value);
Object destRef = ctx.get(valueClass, refId);
if (destRef != null){
// use value from the persistence context
} else if (maxDepth > 1){
// recursively copy ...
destRef = refDesc.createCopy(value, ctx, maxDepth - 1);
} else {
destRef = refDesc.createReference(ctx.isVanillaMode(), refId, destBean, null);
}
setValue(destBean, destRef);
}
}
}
private final class Embedded extends LocalHelp {
void copyProperty(Object sourceBean, Object destBean, CopyContext ctx, int maxDepth){
Object srcEmb = getValue(sourceBean);
if (srcEmb != null){
Object dstEmb = targetDescriptor.createBean(ctx.isVanillaMode());
for (int i = 0; i < embeddedProps.length; i++) {
embeddedProps[i].copyProperty(srcEmb, dstEmb, ctx, maxDepth);
}
setValue(destBean, dstEmb);
}
}
void loadIgnore(DbReadContext ctx) {
for (int i = 0; i < embeddedProps.length; i++) {
embeddedProps[i].loadIgnore(ctx);
}
}
@Override
Object readSet(DbReadContext ctx, Object bean, boolean assignable) throws SQLException {
Object dbVal = read(ctx);
if (bean != null && assignable) {
// set back to the parent bean
setValue(bean, dbVal);
ctx.propagateState(dbVal);
return dbVal;
} else {
return null;
}
}
Object read(DbReadContext ctx) throws SQLException {
EntityBean embeddedBean = targetDescriptor.createEntityBean();
boolean notNull = false;
for (int i = 0; i < embeddedProps.length; i++) {
Object value = embeddedProps[i].readSet(ctx, embeddedBean, null);
if (value != null) {
notNull = true;
}
}
if (notNull) {
ctx.propagateState(embeddedBean);
return embeddedBean;
} else {
return null;
}
}
@Override
void appendFrom(DbSqlContext ctx, boolean forceOuterJoin) {
}
@Override
void appendSelect(DbSqlContext ctx, boolean subQuery) {
for (int i = 0; i < embeddedProps.length; i++) {
embeddedProps[i].appendSelect(ctx, subQuery);
}
}
}
/**
* For imported reference - this is the common case.
*/
private final class Reference extends LocalHelp {
private final BeanPropertyAssocOne> beanProp;
Reference(BeanPropertyAssocOne> beanProp) {
this.beanProp = beanProp;
}
void copyProperty(Object sourceBean, Object destBean, CopyContext ctx, int maxDepth){
copy(sourceBean, destBean, ctx, maxDepth);
}
void loadIgnore(DbReadContext ctx) {
targetIdBinder.loadIgnore(ctx);
if (targetInheritInfo != null) {
ctx.getDataReader().incrementPos(1);
}
}
Object readSet(DbReadContext ctx, Object bean, boolean assignable) throws SQLException {
Object val = read(ctx);
if (bean != null && assignable) {
setValue(bean, val);
ctx.propagateState(val);
}
return val;
}
/**
* Read and set a Reference bean.
*/
@Override
Object read(DbReadContext ctx) throws SQLException {
BeanDescriptor> rowDescriptor = null;
Class> rowType = targetType;
if (targetInheritInfo != null) {
// read discriminator to determine the type
InheritInfo rowInheritInfo = targetInheritInfo.readType(ctx);
if (rowInheritInfo != null) {
rowType = rowInheritInfo.getType();
rowDescriptor = rowInheritInfo.getBeanDescriptor();
}
}
// read the foreign key column(s)
Object id = targetIdBinder.read(ctx);
if (id == null) {
return null;
}
// check transaction context to see if it already exists
Object existing = ctx.getPersistenceContext().get(rowType, id);
if (existing != null) {
return existing;
}
// parent always null for this case (but here to document)
Object parent = null;
Object ref = null;
boolean vanillaMode = ctx.isVanillaMode();
int parentState = ctx.getParentState();
ReferenceOptions options = ctx.getReferenceOptionsFor(beanProp);
if (options != null && options.isUseCache()) {
ref = targetDescriptor.cacheGet(id);
if (ref != null) {
if (vanillaMode){
ref = targetDescriptor.createCopy(ref, new CopyContext(true), 5);
} else if (parentState == EntityBeanIntercept.UPDATE){
ref = targetDescriptor.createCopy(ref, new CopyContext(false), 5);
} else if (parentState == EntityBeanIntercept.DEFAULT && !options.isReadOnly()) {
ref = targetDescriptor.createCopy(ref, new CopyContext(false), 5);
}
}
}
boolean createReference = false;
if (ref == null) {
// create a lazy loading reference/proxy
createReference = true;
if (targetInheritInfo != null) {
// for inheritance hierarchy create the correct type for this row...
ref = rowDescriptor.createReference(vanillaMode, id, parent, options);
} else {
ref = targetDescriptor.createReference(vanillaMode, id, parent, options);
}
}
Object existingBean = ctx.getPersistenceContext().putIfAbsent(id, ref);
if (existingBean != null) {
// advanced case when we use multiple concurrent threads to
// build a single object graph, and another thread has since
// loaded a matching bean so we will use that instead.
ref = existingBean;
createReference = false;
}
if (!vanillaMode){
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
if (createReference) {
if (parentState != 0){
ebi.setState(parentState);
}
ctx.register(name, ebi);
}
}
return ref;
}
@Override
void appendFrom(DbSqlContext ctx, boolean forceOuterJoin) {
if (targetInheritInfo != null) {
// add join to support the discriminator column
String relativePrefix = ctx.getRelativePrefix(name);
tableJoin.addJoin(forceOuterJoin, relativePrefix, ctx);
}
}
/**
* Append columns for foreign key columns.
*/
@Override
void appendSelect(DbSqlContext ctx, boolean subQuery) {
if (!subQuery && targetInheritInfo != null) {
// add discriminator column
String relativePrefix = ctx.getRelativePrefix(getName());
String tableAlias = ctx.getTableAlias(relativePrefix);
ctx.appendColumn(tableAlias, targetInheritInfo.getDiscriminatorColumn());
}
importedId.sqlAppend(ctx);
}
}
/**
* For OneToOne exported reference - not so common.
*/
private final class ReferenceExported extends LocalHelp {
void copyProperty(Object sourceBean, Object destBean, CopyContext ctx, int maxDepth){
copy(sourceBean, destBean, ctx, maxDepth);
}
@Override
void loadIgnore(DbReadContext ctx) {
targetDescriptor.getIdBinder().loadIgnore(ctx);
}
/**
* Read and set a Reference bean.
*/
@Override
Object readSet(DbReadContext ctx, Object bean, boolean assignable) throws SQLException {
Object dbVal = read(ctx);
if (bean != null && assignable) {
setValue(bean, dbVal);
ctx.propagateState(dbVal);
}
return dbVal;
}
@Override
Object read(DbReadContext ctx) throws SQLException {
// TODO: Support for Inheritance hierarchy on exported OneToOne ?
IdBinder idBinder = targetDescriptor.getIdBinder();
Object id = idBinder.read(ctx);
if (id == null) {
return null;
}
PersistenceContext persistCtx = ctx.getPersistenceContext();
Object existing = persistCtx.get(targetType, id);
if (existing != null) {
return existing;
}
boolean vanillaMode = ctx.isVanillaMode();
Object parent = null;
Object ref = targetDescriptor.createReference(vanillaMode, id, parent, null);
if (!vanillaMode){
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
if (ctx.getParentState() != 0) {
ebi.setState(ctx.getParentState());
}
persistCtx.put(id, ref);
ctx.register(name, ebi);
}
return ref;
}
/**
* Append columns for foreign key columns.
*/
@Override
void appendSelect(DbSqlContext ctx, boolean subQuery) {
// set appropriate tableAlias for
// the exported id columns
String relativePrefix = ctx.getRelativePrefix(getName());
ctx.pushTableAlias(relativePrefix);
IdBinder idBinder = targetDescriptor.getIdBinder();
idBinder.appendSelect(ctx, subQuery);
ctx.popTableAlias();
}
@Override
void appendFrom(DbSqlContext ctx, boolean forceOuterJoin) {
String relativePrefix = ctx.getRelativePrefix(getName());
tableJoin.addJoin(forceOuterJoin, relativePrefix, ctx);
}
}
@Override
public void jsonWrite(WriteJsonContext ctx, Object bean) {
Object value = getValueIntercept(bean);
if (value == null){
ctx.beginAssocOneIsNull(name);
} else {
if (ctx.isParentBean(value)){
// bi-directional and already rendered parent
} else {
ctx.pushParentBean(bean);
ctx.beginAssocOne(name);
BeanDescriptor> refDesc = descriptor.getBeanDescriptor(value.getClass());
refDesc.jsonWrite(ctx, value);
ctx.endAssocOne();
ctx.popParentBean();
}
}
}
@Override
public void jsonRead(ReadJsonContext ctx, Object bean){
T assocBean = targetDescriptor.jsonReadBean(ctx, name);
setValue(bean, assocBean);
}
}