package com.fasterxml.jackson.datatype.hibernate3;
import java.io.IOException;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap;
Serializer to use for values proxied using HibernateProxy
.
TODO: should try to make this work more like Jackson
BeanPropertyWriter
, possibly sub-classing
it -- it handles much of functionality we need, and has
access to more information than value serializers (like
this one) have.
/**
* Serializer to use for values proxied using {@link HibernateProxy}.
*<p>
* TODO: should try to make this work more like Jackson
* <code>BeanPropertyWriter</code>, possibly sub-classing
* it -- it handles much of functionality we need, and has
* access to more information than value serializers (like
* this one) have.
*/
public class HibernateProxySerializer
extends JsonSerializer<HibernateProxy>
implements ContextualSerializer
{
Property that has proxy value to handle
/**
* Property that has proxy value to handle
*/
protected final BeanProperty _property;
protected final boolean _forceLazyLoading;
For efficient serializer lookup, let's use this; most
of the time, there's just one type and one serializer.
/**
* For efficient serializer lookup, let's use this; most
* of the time, there's just one type and one serializer.
*/
protected PropertySerializerMap _dynamicSerializers;
/*
/**********************************************************************
/* Life cycle
/**********************************************************************
*/
public HibernateProxySerializer(boolean forceLazyLoading)
{
_forceLazyLoading = forceLazyLoading;
_dynamicSerializers = PropertySerializerMap.emptyForProperties();
_property = null;
}
public HibernateProxySerializer(boolean forceLazyLoading, BeanProperty property)
{
_forceLazyLoading = forceLazyLoading;
_dynamicSerializers = PropertySerializerMap.emptyForProperties();
_property = property;
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
return new HibernateProxySerializer(this._forceLazyLoading);
}
/*
/**********************************************************************
/* JsonSerializer impl
/**********************************************************************
*/
// since 2.3
@Override
public boolean isEmpty(SerializerProvider provider, HibernateProxy value) {
return (value == null) || (findProxied(value) == null);
}
@Override
public void serialize(HibernateProxy value, JsonGenerator jgen, SerializerProvider provider)
throws IOException
{
Object proxiedValue = findProxied(value);
// TODO: figure out how to suppress nulls, if necessary? (too late for that here)
if (proxiedValue == null) {
provider.defaultSerializeNull(jgen);
return;
}
findSerializer(provider, proxiedValue).serialize(proxiedValue, jgen, provider);
}
@Override
public void serializeWithType(HibernateProxy value, JsonGenerator jgen, SerializerProvider provider,
TypeSerializer typeSer)
throws IOException
{
Object proxiedValue = findProxied(value);
if (proxiedValue == null) {
provider.defaultSerializeNull(jgen);
return;
}
/* This isn't exactly right, since type serializer really refers to proxy
* object, not value. And we really don't either know static type (necessary
* to know how to apply additional type info) or other things;
* so it's not going to work well. But... we'll do out best.
*/
findSerializer(provider, proxiedValue).serializeWithType(proxiedValue, jgen, provider, typeSer);
}
@Override
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
throws JsonMappingException
{
SerializerProvider prov = visitor.getProvider();
if ((prov == null) || (_property == null)) {
super.acceptJsonFormatVisitor(visitor, typeHint);
} else {
JavaType type = _property.getType();
prov.findPrimaryPropertySerializer(type, _property)
.acceptJsonFormatVisitor(visitor, type);
}
}
/*
/**********************************************************************
/* Helper methods
/**********************************************************************
*/
protected JsonSerializer<Object> findSerializer(SerializerProvider provider, Object value)
throws IOException
{
/* TODO: if Hibernate did use generics, or we wanted to allow use of Jackson
* annotations to indicate type, should take that into account.
*/
Class<?> rawType = value.getClass();
/* we will use a map to contain serializers found so far, keyed by type:
* this avoids potentially costly lookup from global caches and/or construction
* of new serializers
*/
/* 18-Oct-2013, tatu: Whether this is for the primary property or secondary is
* really anyone's guess at this point; proxies can exist at any level?
*/
PropertySerializerMap.SerializerAndMapResult result =
_dynamicSerializers.findAndAddPrimarySerializer(rawType, provider, _property);
if (_dynamicSerializers != result.map) {
_dynamicSerializers = result.map;
}
return result.serializer;
}
Helper method for finding value being proxied, if it is available
or if it is to be forced to be loaded.
/**
* Helper method for finding value being proxied, if it is available
* or if it is to be forced to be loaded.
*/
protected Object findProxied(HibernateProxy proxy)
{
LazyInitializer init = proxy.getHibernateLazyInitializer();
if (!_forceLazyLoading && init.isUninitialized()) {
return null;
}
return init.getImplementation();
}
}