mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-23 14:32:04 +00:00
#899 - ENH: Add @UnmappedJson support ... (mostly for document store only use / ElasticSearch)
This commit is contained in:
@@ -41,7 +41,7 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>1.2</version>
|
||||
<version>1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -213,6 +213,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
|
||||
private final boolean draftableElement;
|
||||
|
||||
private final BeanProperty unmappedJson;
|
||||
|
||||
private final BeanProperty draft;
|
||||
|
||||
private final BeanProperty draftDirty;
|
||||
@@ -462,6 +464,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
this.softDelete = (softDeleteProperty != null);
|
||||
this.idProperty = listHelper.getId();
|
||||
this.versionProperty = listHelper.getVersionProperty();
|
||||
this.unmappedJson = listHelper.getUnmappedJson();
|
||||
this.draft = listHelper.getDraft();
|
||||
this.draftDirty = listHelper.getDraftDirty();
|
||||
this.propMap = listHelper.getPropertyMap();
|
||||
@@ -474,7 +477,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
this.propertiesMutable = listHelper.getMutable();
|
||||
this.unidirectional = listHelper.getUnidirectional();
|
||||
this.propertiesOne = listHelper.getOnes();
|
||||
//this.propertiesOneExported = listHelper.getOneExported();
|
||||
this.propertiesOneExportedSave = listHelper.getOneExportedSave();
|
||||
this.propertiesOneExportedDelete = listHelper.getOneExportedDelete();
|
||||
this.propertiesOneImported = listHelper.getOneImported();
|
||||
@@ -2468,6 +2470,12 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return draftableElement;
|
||||
}
|
||||
|
||||
public void setUnmappedJson(EntityBean bean, Map<String, Object> unmappedProperties) {
|
||||
if( unmappedJson != null) {
|
||||
unmappedJson.setValueIntercept(bean, unmappedProperties);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the draft to true for this entity bean instance.
|
||||
* This bean is being loaded via asDraft() query.
|
||||
@@ -2597,6 +2605,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return propMap.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property that holds unmapped JSON content.
|
||||
*/
|
||||
public BeanProperty propertyUnmappedJson() {
|
||||
return unmappedJson;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the non transient non id properties.
|
||||
*/
|
||||
|
||||
@@ -159,6 +159,9 @@ public class BeanDescriptorJsonHelp<T> {
|
||||
|
||||
} while (true);
|
||||
|
||||
if (unmappedProperties != null) {
|
||||
desc.setUnmappedJson(bean, unmappedProperties);
|
||||
}
|
||||
Object contextBean = null;
|
||||
Object id = desc.beanId(bean);
|
||||
if (id != null) {
|
||||
|
||||
@@ -242,8 +242,8 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
int deployOrder;
|
||||
|
||||
final boolean jsonSerialize;
|
||||
|
||||
final boolean jsonDeserialize;
|
||||
final boolean unmappedJson;
|
||||
|
||||
final boolean draft;
|
||||
|
||||
@@ -279,6 +279,7 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
this.dbInsertable = deploy.isDbInsertable();
|
||||
this.dbUpdatable = deploy.isDbUpdateable();
|
||||
this.excludedFromHistory = deploy.isExcludedFromHistory();
|
||||
this.unmappedJson = deploy.isUnmappedJson();
|
||||
this.draft = deploy.isDraft();
|
||||
this.draftDirty = deploy.isDraftDirty();
|
||||
this.draftOnly = deploy.isDraftOnly();
|
||||
@@ -426,6 +427,7 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
this.propertyType = source.getPropertyType();
|
||||
this.field = source.getField();
|
||||
this.docOptions = source.docOptions;
|
||||
this.unmappedJson = source.unmappedJson;
|
||||
|
||||
this.elPrefix = override.replace(source.elPrefix, source.dbColumn);
|
||||
this.elPlaceHolder = override.replace(source.elPlaceHolder, source.dbColumn);
|
||||
@@ -1201,6 +1203,13 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
return !excludedFromHistory && descriptor.isHistorySupport();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this property hold unmapped JSON.
|
||||
*/
|
||||
public boolean isUnmappedJson() {
|
||||
return unmappedJson;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this property only exists on the draft table.
|
||||
*/
|
||||
@@ -1302,6 +1311,10 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isJsonSerialize() {
|
||||
return jsonSerialize;
|
||||
}
|
||||
|
||||
@SuppressWarnings(value = "unchecked")
|
||||
public void jsonWrite(WriteJson writeJson, EntityBean bean) throws IOException {
|
||||
if (!jsonSerialize) {
|
||||
|
||||
@@ -203,6 +203,7 @@ public class DeployBeanProperty {
|
||||
private boolean draftReset;
|
||||
|
||||
private boolean softDelete;
|
||||
private boolean unmappedJson;
|
||||
|
||||
private String dbComment;
|
||||
|
||||
@@ -939,6 +940,15 @@ public class DeployBeanProperty {
|
||||
return softDelete;
|
||||
}
|
||||
|
||||
public void setUnmappedJson() {
|
||||
this.unmappedJson = true;
|
||||
this.isTransient = true;
|
||||
}
|
||||
|
||||
public boolean isUnmappedJson() {
|
||||
return unmappedJson;
|
||||
}
|
||||
|
||||
public void setDbComment(String dbComment) {
|
||||
this.dbComment = dbComment;
|
||||
}
|
||||
@@ -966,4 +976,5 @@ public class DeployBeanProperty {
|
||||
public String getDbColumnDefault() {
|
||||
return dbColumnDefault;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-2
@@ -27,6 +27,8 @@ public class DeployBeanPropertyLists {
|
||||
|
||||
private BeanProperty versionProperty;
|
||||
|
||||
private BeanProperty unmappedJson;
|
||||
|
||||
private BeanProperty draft;
|
||||
|
||||
private BeanProperty draftDirty;
|
||||
@@ -167,6 +169,9 @@ public class DeployBeanPropertyLists {
|
||||
if (prop.isDraft()) {
|
||||
draft = prop;
|
||||
}
|
||||
if (prop.isUnmappedJson()) {
|
||||
unmappedJson = prop;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (prop.isId()) {
|
||||
@@ -205,8 +210,7 @@ public class DeployBeanPropertyLists {
|
||||
if (versionProperty == null) {
|
||||
versionProperty = prop;
|
||||
} else {
|
||||
logger.warn("Multiple @Version properties - property " + prop.getFullBeanName()
|
||||
+ " not treated as a version property");
|
||||
logger.warn("Multiple @Version properties - property " + prop.getFullBeanName() + " not treated as a version property");
|
||||
}
|
||||
} else if (prop.isDraftDirty()) {
|
||||
draftDirty = prop;
|
||||
@@ -326,6 +330,10 @@ public class DeployBeanPropertyLists {
|
||||
return draftDirty;
|
||||
}
|
||||
|
||||
public BeanProperty getUnmappedJson() {
|
||||
return unmappedJson;
|
||||
}
|
||||
|
||||
public BeanProperty getDraft() {
|
||||
return draft;
|
||||
}
|
||||
|
||||
@@ -13,9 +13,6 @@ import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundType;
|
||||
import com.avaje.ebeaninternal.server.type.DataEncryptSupport;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeBytesBase;
|
||||
@@ -26,7 +23,6 @@ import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.sql.Types;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -364,6 +360,9 @@ public class AnnotationFields extends AnnotationParser {
|
||||
prop.setJsonSerialize(jsonIgnore.serialize());
|
||||
prop.setJsonDeserialize(jsonIgnore.deserialize());
|
||||
}
|
||||
if (get(prop, UnmappedJson.class) != null) {
|
||||
prop.setUnmappedJson();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasRelationshipItem(DeployBeanProperty prop) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.text.json;
|
||||
import com.avaje.ebean.FetchPath;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.config.JsonConfig;
|
||||
import com.avaje.ebean.text.json.EJson;
|
||||
import com.avaje.ebean.text.json.JsonIOException;
|
||||
import com.avaje.ebean.text.json.JsonWriteBeanVisitor;
|
||||
import com.avaje.ebean.text.json.JsonWriter;
|
||||
@@ -465,7 +466,9 @@ public class WriteJson implements JsonWriter {
|
||||
}
|
||||
|
||||
private boolean isIncludeTransientProperty(BeanProperty prop) {
|
||||
if (!explicitAllProps && currentIncludeProps != null) {
|
||||
if (prop.isUnmappedJson()) {
|
||||
return false;
|
||||
} else if (!explicitAllProps && currentIncludeProps != null) {
|
||||
// explicitly controlled by pathProperties
|
||||
return currentIncludeProps.contains(prop.getName());
|
||||
} else {
|
||||
@@ -501,6 +504,18 @@ public class WriteJson implements JsonWriter {
|
||||
}
|
||||
}
|
||||
|
||||
BeanProperty unmappedJson = desc.propertyUnmappedJson();
|
||||
if (unmappedJson != null && unmappedJson.isJsonSerialize()) {
|
||||
Map<String,Object> map = (Map<String,Object>)unmappedJson.getValue(currentBean);
|
||||
if (map != null) {
|
||||
// write to JSON at the current level
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
writeJson.writeFieldName(entry.getKey());
|
||||
EJson.write(entry.getValue(), writeJson.generator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (visitor != null) {
|
||||
visitor.visit(currentBean, writeJson);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.avaje.tests.json;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.tests.model.json.EBasicJsonUnmapped;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestUnmappedProperties extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void toJson() {
|
||||
|
||||
Map<String,Object> nested = new LinkedHashMap<>();
|
||||
nested.put("alpha", "aa");
|
||||
nested.put("beta", "bb");
|
||||
|
||||
|
||||
Map<String,Object> unmapped = new LinkedHashMap<>();
|
||||
unmapped.put("one", 42);
|
||||
unmapped.put("nested", nested);
|
||||
|
||||
EBasicJsonUnmapped bean = new EBasicJsonUnmapped();
|
||||
bean.setName("someName");
|
||||
bean.setUnmapped(unmapped);
|
||||
|
||||
|
||||
String asJson = Ebean.json().toJson(bean);
|
||||
|
||||
assertThat(asJson).contains("{\"name\":\"someName\",\"one\":42,\"nested\":{\"alpha\":\"aa\",\"beta\":\"bb\"}}");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromJson() {
|
||||
|
||||
String json = "{\"name\":\"someName\",\"one\":42,\"nested\":{\"alpha\":\"aa\",\"beta\":\"bb\"}}";
|
||||
|
||||
EBasicJsonUnmapped bean = Ebean.json().toBean(EBasicJsonUnmapped.class, json);
|
||||
|
||||
assertThat(bean.getName()).isEqualTo("someName");
|
||||
assertThat(bean.getUnmapped().get("one")).isEqualTo(42L);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String,Object> fromNested = (Map<String,Object>)bean.getUnmapped().get("nested");
|
||||
assertThat(fromNested).containsKeys("alpha", "beta");
|
||||
assertThat(fromNested).containsValues("aa", "bb");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.avaje.tests.model.json;
|
||||
|
||||
import com.avaje.ebean.annotation.UnmappedJson;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Version;
|
||||
import java.util.Map;
|
||||
|
||||
@Entity
|
||||
public class EBasicJsonUnmapped {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@Version
|
||||
Long version;
|
||||
|
||||
String name;
|
||||
|
||||
@UnmappedJson
|
||||
Map<String, Object> unmapped;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(Long version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Map<String, Object> getUnmapped() {
|
||||
return unmapped;
|
||||
}
|
||||
|
||||
public void setUnmapped(Map<String, Object> unmapped) {
|
||||
this.unmapped = unmapped;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user