diff --git a/ebean-api/src/main/java/io/ebean/text/json/JsonWriteOptions.java b/ebean-api/src/main/java/io/ebean/text/json/JsonWriteOptions.java index 7995f7a84..913ac4114 100644 --- a/ebean-api/src/main/java/io/ebean/text/json/JsonWriteOptions.java +++ b/ebean-api/src/main/java/io/ebean/text/json/JsonWriteOptions.java @@ -22,6 +22,8 @@ public class JsonWriteOptions { protected JsonConfig.Include include; + protected boolean includeLoadedImplicit = true; + protected Map> visitorMap; /** @@ -73,6 +75,20 @@ public class JsonWriteOptions { this.include = include; } + /** + * Should loaded properties be included implicit, if no other fetch path is specified (default = true). + */ + public boolean isIncludeLoadedImplicit() { + return includeLoadedImplicit; + } + + /** + * Set include loaded properties implicit (default = true). + */ + public void setIncludeLoadedImplicit(boolean includeLoadedImplicit) { + this.includeLoadedImplicit = includeLoadedImplicit; + } + /** * Register a JsonWriteBeanVisitor for the root level. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/json/DJsonContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/json/DJsonContext.java index 340f978e1..39b80344b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/json/DJsonContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/json/DJsonContext.java @@ -402,7 +402,13 @@ public final class DJsonContext implements SpiJsonContext { private WriteJson createWriteJson(JsonGenerator gen, JsonWriteOptions options) { FetchPath pathProps = (options == null) ? null : options.getPathProperties(); Map> visitors = (options == null) ? null : options.getVisitorMap(); - return new WriteJson(server, gen, pathProps, visitors, determineObjectMapper(options), determineInclude(options)); + return new WriteJson(server, + gen, + pathProps, + visitors, + determineObjectMapper(options), + determineInclude(options), + options == null || options.isIncludeLoadedImplicit()); } private void toJsonFromCollection(Collection collection, String key, JsonGenerator gen, JsonWriteOptions options) throws IOException { @@ -490,4 +496,5 @@ public final class DJsonContext implements SpiJsonContext { JsonConfig.Include include = options.getInclude(); return (include != null) ? include : defaultInclude; } + } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/json/WriteJson.java b/ebean-core/src/main/java/io/ebeaninternal/server/json/WriteJson.java index 39e03eb95..f5b583822 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/json/WriteJson.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/json/WriteJson.java @@ -31,12 +31,15 @@ public final class WriteJson implements SpiJsonWriter { private final ArrayStack parentBeans; private final Object objectMapper; private final JsonConfig.Include include; + private final boolean includeLoadedImplicit; + /** * Construct for full bean use (normal). */ public WriteJson(SpiEbeanServer server, JsonGenerator generator, FetchPath fetchPath, - Map> visitors, Object objectMapper, JsonConfig.Include include) { + Map> visitors, Object objectMapper, JsonConfig.Include include, + boolean includeLoadedImplicit) { this.server = server; this.generator = generator; @@ -44,6 +47,7 @@ public final class WriteJson implements SpiJsonWriter { this.visitors = visitors; this.objectMapper = objectMapper; this.include = include; + this.includeLoadedImplicit = includeLoadedImplicit; this.parentBeans = new ArrayStack<>(); this.pathStack = new PathStack(); } @@ -54,6 +58,7 @@ public final class WriteJson implements SpiJsonWriter { public WriteJson(JsonGenerator generator, JsonConfig.Include include) { this.generator = generator; this.include = include; + this.includeLoadedImplicit = true; this.visitors = null; this.server = null; this.fetchPath = null; @@ -443,7 +448,7 @@ public final class WriteJson implements SpiJsonWriter { currentIncludeProps = null; } } - return new WriteBean(desc, explicitAllProps, currentIncludeProps, bean, visitor); + return new WriteBean(desc, explicitAllProps, includeLoadedImplicit, currentIncludeProps, bean, visitor); } @Override @@ -477,6 +482,7 @@ public final class WriteJson implements SpiJsonWriter { public static class WriteBean { final boolean explicitAllProps; + final boolean includeLoadedImplicit; final Set currentIncludeProps; final BeanDescriptor desc; final EntityBean currentBean; @@ -485,14 +491,15 @@ public final class WriteJson implements SpiJsonWriter { final JsonWriteBeanVisitor visitor; WriteBean(BeanDescriptor desc, EntityBean currentBean, JsonWriteBeanVisitor visitor) { - this(desc, false, null, currentBean, visitor); + this(desc, false, true, null, currentBean, visitor); } - WriteBean(BeanDescriptor desc, boolean explicitAllProps, Set currentIncludeProps, EntityBean currentBean, JsonWriteBeanVisitor visitor) { + WriteBean(BeanDescriptor desc, boolean explicitAllProps, boolean includeLoadedImplicit, Set currentIncludeProps, EntityBean currentBean, JsonWriteBeanVisitor visitor) { super(); this.desc = desc; this.currentBean = currentBean; this.explicitAllProps = explicitAllProps; + this.includeLoadedImplicit = includeLoadedImplicit; this.currentIncludeProps = currentIncludeProps; this.visitor = visitor; } @@ -507,9 +514,11 @@ public final class WriteJson implements SpiJsonWriter { if (currentIncludeProps != null) { // explicitly controlled by pathProperties return currentIncludeProps.contains(prop.name()); - } else { + } else if (includeLoadedImplicit){ // include only loaded properties return currentBean._ebean_getIntercept().isLoadedProperty(prop.propertyIndex()); + } else { + return prop.isId(); } } diff --git a/ebean-test/src/test/java/io/ebean/xtest/internal/server/text/json/WriteJsonDirtyTest.java b/ebean-test/src/test/java/io/ebean/xtest/internal/server/text/json/WriteJsonDirtyTest.java index 4918a243b..f18a5cb82 100644 --- a/ebean-test/src/test/java/io/ebean/xtest/internal/server/text/json/WriteJsonDirtyTest.java +++ b/ebean-test/src/test/java/io/ebean/xtest/internal/server/text/json/WriteJsonDirtyTest.java @@ -43,7 +43,7 @@ public class WriteJsonDirtyTest { JsonFactory jsonFactory = new JsonFactory(); JsonGenerator generator = jsonFactory.createGenerator(writer); - WriteJson writeJson = new WriteJson(server, generator, null, null, null, null); + WriteJson writeJson = new WriteJson(server, generator, null, null, null, null, true); descriptor.jsonWriteDirty(writeJson, entityBean, dirtyProperties); generator.flush(); diff --git a/ebean-test/src/test/java/org/tests/json/include/TestJsonImplicitLoaded.java b/ebean-test/src/test/java/org/tests/json/include/TestJsonImplicitLoaded.java new file mode 100644 index 000000000..ca930df30 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/json/include/TestJsonImplicitLoaded.java @@ -0,0 +1,41 @@ +package org.tests.json.include; + +import io.ebean.DB; +import io.ebean.FetchPath; +import io.ebean.annotation.Transactional; +import io.ebean.config.JsonConfig; +import io.ebean.text.PathProperties; +import io.ebean.text.json.JsonWriteOptions; +import org.junit.jupiter.api.Test; +import org.tests.model.basic.Contact; +import org.tests.model.basic.ResetBasicData; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestJsonImplicitLoaded { + + @Test + @Transactional + public void testToBeanToJson() throws Exception { + ResetBasicData.reset(); + + + FetchPath path = PathProperties.parse("*"); + Contact bean = DB.find(Contact.class).setId(1).apply(path).findOne(); + + JsonWriteOptions options = new JsonWriteOptions(); + options.setInclude(JsonConfig.Include.NON_NULL); + options.setPathProperties(path); + options.setIncludeLoadedImplicit(false); + + String asJson = DB.json().toJson(bean, options); + assertThat(asJson).contains("customer\":{\"id\":1}"); // hold only ID + + bean.getCustomer().getName(); // lazy-load bean; + asJson = DB.json().toJson(bean, options); + assertThat(asJson).contains("customer\":{\"id\":1}"); // expect the same result + + + } + +}