Skip to content

Commit c900ad4

Browse files
authored
Merge pull request #95 from NagyGa1/issue-93-strip-persistenc-collections
New feature: `REPLACE_PERSISTENT_COLLECTIONS` to fix #93
2 parents a71591e + e2a959b commit c900ad4

File tree

11 files changed

+531
-6
lines changed

11 files changed

+531
-6
lines changed

hibernate3/src/main/java/com/fasterxml/jackson/datatype/hibernate3/Hibernate3Module.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ public enum Feature {
4444
* @since 2.4
4545
*/
4646
REQUIRE_EXPLICIT_LAZY_LOADING_MARKER(false),
47+
48+
/**
49+
* Replaces org.hibernate.collection.spi.PersistentCollection List, Set, Map subclasses to java.util.ArrayList, HashSet,
50+
* HashMap, during Serialization.
51+
* <p>
52+
* Default is false.
53+
*
54+
* @since 2.8.2
55+
*/
56+
REPLACE_PERSISTENT_COLLECTIONS(false)
4757
;
4858

4959
final boolean _defaultState;

hibernate3/src/main/java/com/fasterxml/jackson/datatype/hibernate3/PersistentCollectionSerializer.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
package com.fasterxml.jackson.datatype.hibernate3;
22

33
import java.io.IOException;
4+
import java.util.ArrayList;
45
import java.util.Collection;
6+
import java.util.HashMap;
7+
import java.util.HashSet;
8+
import java.util.List;
59
import java.util.Map;
10+
import java.util.Set;
611

712
import javax.persistence.*;
813

@@ -21,6 +26,7 @@
2126
import org.hibernate.engine.SessionFactoryImplementor;
2227
import org.hibernate.engine.SessionImplementor;
2328
import org.hibernate.impl.SessionFactoryImpl;
29+
import org.hibernate.mapping.Bag;
2430
import org.hibernate.transaction.JDBCTransactionFactory;
2531
import org.hibernate.transaction.TransactionFactory;
2632

@@ -256,6 +262,11 @@ public void serialize(Object value, JsonGenerator jgen, SerializerProvider provi
256262
if (_serializer == null) { // sanity check...
257263
throw JsonMappingException.from(jgen, "PersistentCollection does not have serializer set");
258264
}
265+
266+
if (Feature.REPLACE_PERSISTENT_COLLECTIONS.enabledIn(_features)) {
267+
value = convertToJavaCollection(value); // Strip PersistentCollection
268+
}
269+
259270
_serializer.serialize(value, jgen, provider);
260271
}
261272

@@ -279,6 +290,11 @@ public void serializeWithType(Object value, JsonGenerator jgen, SerializerProvid
279290
if (_serializer == null) { // sanity check...
280291
throw JsonMappingException.from(jgen, "PersistentCollection does not have serializer set");
281292
}
293+
294+
if (Feature.REPLACE_PERSISTENT_COLLECTIONS.enabledIn(_features)) {
295+
value = convertToJavaCollection(value); // Strip PersistentCollection
296+
}
297+
282298
_serializer.serializeWithType(value, jgen, provider, typeSer);
283299
}
284300

@@ -384,4 +400,38 @@ protected boolean usesLazyLoading(BeanProperty property)
384400
}
385401
return false;
386402
}
403+
404+
private Object convertToJavaCollection(Object value) {
405+
if (!(value instanceof PersistentCollection)) {
406+
return value;
407+
}
408+
409+
if (value instanceof Set) {
410+
return convertToSet((Set<?>) value);
411+
}
412+
413+
if (value instanceof List
414+
|| value instanceof Bag
415+
) {
416+
return convertToList((List<?>) value);
417+
}
418+
419+
if (value instanceof Map) {
420+
return convertToMap((Map<?, ?>) value);
421+
}
422+
423+
throw new IllegalArgumentException("Unsupported type: " + value.getClass());
424+
}
425+
426+
private Object convertToList(List<?> value) {
427+
return new ArrayList<>(value);
428+
}
429+
430+
private Object convertToMap(Map<?, ?> value) {
431+
return new HashMap<>(value);
432+
}
433+
434+
private Object convertToSet(Set<?> value) {
435+
return new HashSet<>(value);
436+
}
387437
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package com.fasterxml.jackson.datatype.hibernate3;
2+
3+
import com.fasterxml.jackson.databind.JsonMappingException;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.fasterxml.jackson.datatype.hibernate3.data.Customer;
6+
import com.fasterxml.jackson.datatype.hibernate3.data.Payment;
7+
import org.hibernate.Hibernate;
8+
import org.junit.After;
9+
import org.junit.Assert;
10+
import org.junit.Before;
11+
import org.junit.Test;
12+
13+
import javax.persistence.EntityManager;
14+
import javax.persistence.EntityManagerFactory;
15+
import javax.persistence.Persistence;
16+
import java.util.Map;
17+
import java.util.Set;
18+
19+
public class ReplacePersistentCollectionTest {
20+
21+
private EntityManagerFactory emf;
22+
23+
private EntityManager em;
24+
25+
@Before
26+
public void setUp() throws Exception {
27+
emf = Persistence.createEntityManagerFactory("persistenceUnit");
28+
em = emf.createEntityManager();
29+
}
30+
31+
@After
32+
public void tearDown() throws Exception {
33+
em.close();
34+
emf.close();
35+
}
36+
37+
// [Issue#93], backwards compatible case
38+
@Test
39+
public void testNoReplacePersistentCollection() throws Exception {
40+
final ObjectMapper mapper = new ObjectMapper()
41+
.registerModule(new Hibernate3Module()
42+
.configure(Hibernate3Module.Feature.FORCE_LAZY_LOADING, true)
43+
).enableDefaultTyping();
44+
45+
Customer customer = em.find(Customer.class, 103);
46+
Assert.assertFalse(Hibernate.isInitialized(customer.getPayments()));
47+
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(customer);
48+
Assert.assertTrue(json.contains("org.hibernate.collection"));
49+
// should force loading...
50+
Set<Payment> payments = customer.getPayments();
51+
/*
52+
System.out.println("--- JSON ---");
53+
System.out.println(json);
54+
System.out.println("--- /JSON ---");
55+
*/
56+
57+
Assert.assertTrue(Hibernate.isInitialized(payments));
58+
// TODO: verify
59+
Assert.assertNotNull(json);
60+
61+
boolean exceptionThrown = false;
62+
try {
63+
Map<?, ?> stuff = mapper.readValue(json, Map.class);
64+
} catch (JsonMappingException e) {
65+
exceptionThrown = true;
66+
}
67+
Assert.assertTrue(exceptionThrown);
68+
}
69+
70+
// [Issue#93], backwards compatible case
71+
@Test
72+
public void testReplacePersistentCollection() throws Exception {
73+
final ObjectMapper mapper = new ObjectMapper()
74+
.registerModule(new Hibernate3Module()
75+
.configure(Hibernate3Module.Feature.FORCE_LAZY_LOADING, true)
76+
.configure(Hibernate3Module.Feature.REPLACE_PERSISTENT_COLLECTIONS, true)
77+
).enableDefaultTyping();
78+
79+
Customer customer = em.find(Customer.class, 103);
80+
Assert.assertFalse(Hibernate.isInitialized(customer.getPayments()));
81+
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(customer);
82+
Assert.assertFalse(json.contains("org.hibernate.collection"));
83+
// should force loading...
84+
Set<Payment> payments = customer.getPayments();
85+
/*
86+
System.out.println("--- JSON ---");
87+
System.out.println(json);
88+
System.out.println("--- /JSON ---");
89+
*/
90+
91+
Assert.assertTrue(Hibernate.isInitialized(payments));
92+
// TODO: verify
93+
Assert.assertNotNull(json);
94+
95+
/*
96+
* Currently this cannot be verified due to Issue#94 default typing fails on 2.7.0 - 2.8.2-SNAPSHOT,
97+
* commented out until that is fixed.
98+
*/
99+
100+
boolean issue94failed = false;
101+
try {
102+
Map<?, ?> stuff = mapper.readValue(json, Map.class);
103+
} catch (JsonMappingException e) {
104+
issue94failed = true;
105+
}
106+
107+
Assert.assertTrue("If this fails, means #94 is fixed. Replace to the below commented lines", issue94failed);
108+
109+
// Map<?, ?> stuff = mapper.readValue(json, Map.class);
110+
//
111+
// Assert.assertTrue(stuff.containsKey("payments"));
112+
// Assert.assertTrue(stuff.containsKey("orders"));
113+
// Assert.assertNull(stuff.get("orderes"));
114+
}
115+
}

hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/Hibernate4Module.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,16 @@ public enum Feature {
5454
* @since 2.4
5555
*/
5656
REQUIRE_EXPLICIT_LAZY_LOADING_MARKER(false),
57+
58+
/**
59+
* Replaces org.hibernate.collection.spi.PersistentCollection List, Set, Map subclasses to java.util.ArrayList, HashSet,
60+
* HashMap, during Serialization.
61+
* <p>
62+
* Default is false.
63+
*
64+
* @since 2.8.2
65+
*/
66+
REPLACE_PERSISTENT_COLLECTIONS(false)
5767
;
5868

5969
final boolean _defaultState;

hibernate4/src/main/java/com/fasterxml/jackson/datatype/hibernate4/PersistentCollectionSerializer.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,18 @@
1818
import org.hibernate.engine.spi.PersistenceContext;
1919
import org.hibernate.engine.spi.SessionFactoryImplementor;
2020
import org.hibernate.engine.spi.SessionImplementor;
21+
import org.hibernate.mapping.Bag;
2122

2223
import javax.persistence.*;
2324

2425
import java.io.IOException;
26+
import java.util.ArrayList;
2527
import java.util.Collection;
28+
import java.util.HashMap;
29+
import java.util.HashSet;
30+
import java.util.List;
2631
import java.util.Map;
32+
import java.util.Set;
2733

2834
/**
2935
* Wrapper serializer used to handle aspects of lazy loading that can be used
@@ -250,6 +256,11 @@ public void serialize(Object value, JsonGenerator jgen, SerializerProvider provi
250256
if (_serializer == null) { // sanity check...
251257
throw JsonMappingException.from(jgen, "PersistentCollection does not have serializer set");
252258
}
259+
260+
if (Feature.REPLACE_PERSISTENT_COLLECTIONS.enabledIn(_features)) {
261+
value = convertToJavaCollection(value); // Strip PersistentCollection
262+
}
263+
253264
_serializer.serialize(value, jgen, provider);
254265
}
255266

@@ -268,6 +279,11 @@ public void serializeWithType(Object value, JsonGenerator jgen, SerializerProvid
268279
if (_serializer == null) { // sanity check...
269280
throw JsonMappingException.from(jgen, "PersistentCollection does not have serializer set");
270281
}
282+
283+
if (Feature.REPLACE_PERSISTENT_COLLECTIONS.enabledIn(_features)) {
284+
value = convertToJavaCollection(value); // Strip PersistentCollection
285+
}
286+
271287
_serializer.serializeWithType(value, jgen, provider, typeSer);
272288
}
273289

@@ -368,4 +384,38 @@ protected boolean usesLazyLoading(BeanProperty property) {
368384
}
369385
return false;
370386
}
387+
388+
private Object convertToJavaCollection(Object value) {
389+
if (!(value instanceof PersistentCollection)) {
390+
return value;
391+
}
392+
393+
if (value instanceof Set) {
394+
return convertToSet((Set<?>) value);
395+
}
396+
397+
if (value instanceof List
398+
|| value instanceof Bag
399+
) {
400+
return convertToList((List<?>) value);
401+
}
402+
403+
if (value instanceof Map) {
404+
return convertToMap((Map<?, ?>) value);
405+
}
406+
407+
throw new IllegalArgumentException("Unsupported type: " + value.getClass());
408+
}
409+
410+
private Object convertToList(List<?> value) {
411+
return new ArrayList<>(value);
412+
}
413+
414+
private Object convertToMap(Map<?, ?> value) {
415+
return new HashMap<>(value);
416+
}
417+
418+
private Object convertToSet(Set<?> value) {
419+
return new HashSet<>(value);
420+
}
371421
}

0 commit comments

Comments
 (0)