Skip to content

Fix for #41 inspired by https://github.com/FasterXML/jackson-datatype-hibernate/pull/69 #71

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package com.fasterxml.jackson.datatype.hibernate4;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerBuilder;
import com.fasterxml.jackson.databind.ser.impl.BeanAsArraySerializer;
import com.fasterxml.jackson.databind.ser.impl.ObjectIdWriter;
import com.fasterxml.jackson.databind.ser.impl.UnwrappingBeanSerializer;
import com.fasterxml.jackson.databind.ser.std.BeanSerializerBase;
import com.fasterxml.jackson.databind.util.NameTransformer;

import java.io.IOException;

/**
* Clone of BeanSerializer, because we need to alter serialize method in HibernateProxySerializer
*/
public class ClonedBeanSerializer
extends BeanSerializerBase
{
private static final long serialVersionUID = -4536893235025590367L;

/*
/**********************************************************
/* Life-cycle: constructors
/**********************************************************
*/

/**
* @param builder Builder object that contains collected information
* that may be needed for serializer
* @param properties Property writers used for actual serialization
*/
public ClonedBeanSerializer(JavaType type, BeanSerializerBuilder builder,
BeanPropertyWriter[] properties, BeanPropertyWriter[] filteredProperties)
{
super(type, builder, properties, filteredProperties);
}

/**
* Alternate copy constructor that can be used to construct
* standard {@link ClonedBeanSerializer} passing an instance of
* "compatible enough" source serializer.
*/
protected ClonedBeanSerializer(BeanSerializerBase src) {
super(src);
}

protected ClonedBeanSerializer(BeanSerializerBase src,
ObjectIdWriter objectIdWriter) {
super(src, objectIdWriter);
}

protected ClonedBeanSerializer(BeanSerializerBase src,
ObjectIdWriter objectIdWriter, Object filterId) {
super(src, objectIdWriter, filterId);
}

protected ClonedBeanSerializer(BeanSerializerBase src, String[] toIgnore) {
super(src, toIgnore);
}

/*
/**********************************************************
/* Life-cycle: factory methods, fluent factories
/**********************************************************
*/

/**
* Method for constructing dummy bean serializer; one that
* never outputs any properties
*/
public static ClonedBeanSerializer createDummy(JavaType forType)
{
return new ClonedBeanSerializer(forType, null, NO_PROPS, null);
}

@Override
public JsonSerializer<Object> unwrappingSerializer(NameTransformer unwrapper) {
return new UnwrappingBeanSerializer(this, unwrapper);
}

@Override
public BeanSerializerBase withObjectIdWriter(ObjectIdWriter objectIdWriter) {
return new ClonedBeanSerializer(this, objectIdWriter, _propertyFilterId);
}

@Override
protected BeanSerializerBase withFilterId(Object filterId) {
return new ClonedBeanSerializer(this, _objectIdWriter, filterId);
}

@Override
protected BeanSerializerBase withIgnorals(String[] toIgnore) {
return new ClonedBeanSerializer(this, toIgnore);
}

/**
* Implementation has to check whether as-array serialization
* is possible reliably; if (and only if) so, will construct
* a {@link BeanAsArraySerializer}, otherwise will return this
* serializer as is.
*/
@Override
protected BeanSerializerBase asArraySerializer()
{
/* Can not:
*
* - have Object Id (may be allowed in future)
* - have "any getter"
* - have per-property filters
*/
if ((_objectIdWriter == null)
&& (_anyGetterWriter == null)
&& (_propertyFilterId == null)
) {
return new BeanAsArraySerializer(this);
}
// already is one, so:
return this;
}

/*
/**********************************************************
/* JsonSerializer implementation that differs between impls
/**********************************************************
*/

/**
* Main serialization method that will delegate actual output to
* configured
* {@link BeanPropertyWriter} instances.
*/
@Override
public void serialize(Object bean, JsonGenerator gen, SerializerProvider provider)
throws IOException
{
if (_objectIdWriter != null) {
_serializeWithObjectId(bean, gen, provider, true);
return;
}
gen.writeStartObject();
// [databind#631]: Assign current value, to be accessible by custom serializers
gen.setCurrentValue(bean);
if (_propertyFilterId != null) {
serializeFieldsFiltered(bean, gen, provider);
} else {
serializeFields(bean, gen, provider);
}
gen.writeEndObject();
}

/*
/**********************************************************
/* Standard methods
/**********************************************************
*/

@Override public String toString() {
return "BeanSerializer for "+handledType().getName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
import org.hibernate.SessionFactory;
import org.hibernate.engine.spi.Mapping;

Expand Down Expand Up @@ -137,7 +139,14 @@ public void setupModule(SetupContext context)
if (ai != null) {
context.appendAnnotationIntrospector(ai);
}
context.addSerializers(new HibernateSerializers(_mapping, _moduleFeatures));
ObjectMapper objectMapper = context.getOwner();
DefaultSerializerProvider defaultSerializerProvider = ((DefaultSerializerProvider) objectMapper
.getSerializerProvider());
context.addSerializers(new HibernateSerializers(
defaultSerializerProvider.createInstance(
objectMapper.getSerializationConfig(),
objectMapper.getSerializerFactory()), _mapping,
_moduleFeatures));
context.addBeanSerializerModifier(new HibernateSerializerModifier(_moduleFeatures, _sessionFactory));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
package com.fasterxml.jackson.datatype.hibernate4;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerBuilder;
import com.fasterxml.jackson.databind.ser.impl.ObjectIdWriter;
import com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap;
import com.fasterxml.jackson.databind.ser.std.BeanSerializerBase;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
* Serializer to use for values proxied using {@link org.hibernate.proxy.HibernateProxy}.
Expand All @@ -25,7 +30,7 @@
* this one) have.
*/
public class HibernateProxySerializer
extends JsonSerializer<HibernateProxy>
extends ClonedBeanSerializer
{
/**
* Property that has proxy value to handle
Expand All @@ -48,22 +53,51 @@ public class HibernateProxySerializer
/**********************************************************************
*/

public HibernateProxySerializer(boolean forceLazyLoading)
{
this(forceLazyLoading, false, null);
public HibernateProxySerializer(JavaType type, BeanSerializerBuilder builder,
BeanPropertyWriter[] properties,
BeanPropertyWriter[] filteredProperties,
boolean forceLazyLoading,
boolean serializeIdentifier, Mapping mapping) {
super(type, builder, properties, filteredProperties);
_forceLazyLoading = forceLazyLoading;
_serializeIdentifier = serializeIdentifier;
_mapping = mapping;
_dynamicSerializers = PropertySerializerMap.emptyMap();
_property = null;
}

public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier) {
this(forceLazyLoading, serializeIdentifier, null);
protected HibernateProxySerializer(HibernateProxySerializer hibernateProxySerializer, String[] toIgnore) {
super(hibernateProxySerializer, toIgnore);
_forceLazyLoading = hibernateProxySerializer._forceLazyLoading;
_serializeIdentifier = hibernateProxySerializer._serializeIdentifier;
_mapping = hibernateProxySerializer._mapping;
_dynamicSerializers = PropertySerializerMap.emptyMap();
_property = null;
}

public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdentifier, Mapping mapping) {
_forceLazyLoading = forceLazyLoading;
_serializeIdentifier = serializeIdentifier;
_mapping = mapping;
protected HibernateProxySerializer(HibernateProxySerializer hibernateProxySerializer, ObjectIdWriter objectIdWriter, Object filterId) {
super(hibernateProxySerializer, objectIdWriter, filterId);
_forceLazyLoading = hibernateProxySerializer._forceLazyLoading;
_serializeIdentifier = hibernateProxySerializer._serializeIdentifier;
_mapping = hibernateProxySerializer._mapping;
_dynamicSerializers = PropertySerializerMap.emptyMap();
_property = null;
}

@Override
public BeanSerializerBase withObjectIdWriter(ObjectIdWriter objectIdWriter) {
return new HibernateProxySerializer(this, objectIdWriter, _propertyFilterId);
}

@Override
protected BeanSerializerBase withFilterId(Object filterId) {
return new HibernateProxySerializer(this, _objectIdWriter, filterId);
}

@Override
protected BeanSerializerBase withIgnorals(String[] toIgnore) {
return new HibernateProxySerializer(this, toIgnore);
}

/*
/**********************************************************************
Expand All @@ -73,30 +107,34 @@ public HibernateProxySerializer(boolean forceLazyLoading, boolean serializeIdent

// since 2.3
@Override
public boolean isEmpty(HibernateProxy value)
public boolean isEmpty(Object value)
{
return (value == null) || (findProxied(value) == null);
return (value == null) || (findProxied((HibernateProxy) value) == null);
}

@Override
public void serialize(HibernateProxy value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
throws IOException
{
Object proxiedValue = findProxied(value);
Object proxiedValue = findProxied((HibernateProxy) 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);
if(proxiedValue instanceof Map){
findSerializer(provider, proxiedValue).serialize(proxiedValue, jgen, provider);
} else{
super.serialize(value, jgen, provider);
}
}

@Override
public void serializeWithType(HibernateProxy value, JsonGenerator jgen, SerializerProvider provider,
public void serializeWithType(Object value, JsonGenerator jgen, SerializerProvider provider,
TypeSerializer typeSer)
throws IOException, JsonProcessingException
throws IOException
{
Object proxiedValue = findProxied(value);
Object proxiedValue = findProxied((HibernateProxy) value);
if (proxiedValue == null) {
provider.defaultSerializeNull(jgen);
return;
Expand All @@ -106,7 +144,11 @@ public void serializeWithType(HibernateProxy value, JsonGenerator jgen, Serializ
* 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);
if(proxiedValue instanceof Map) {
findSerializer(provider, proxiedValue).serializeWithType(proxiedValue, jgen, provider, typeSer);
} else{
super.serializeWithType(value, jgen, provider, typeSer);
}
}

/*
Expand All @@ -116,7 +158,7 @@ public void serializeWithType(HibernateProxy value, JsonGenerator jgen, Serializ
*/

protected JsonSerializer<Object> findSerializer(SerializerProvider provider, Object value)
throws IOException, JsonProcessingException
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.
Expand Down
Loading