Added support to include additional properties in Property types

[#20012]
This commit is contained in:
Luca Frosini 2020-11-09 15:46:01 +01:00
parent 1d74ee7905
commit f16b30bd09
6 changed files with 131 additions and 3 deletions

View File

@ -3,7 +3,12 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
# Changelog for Information System Model
## [v4.0.0] [r5.0.0]
## [v4.1.0-SNAPSHOT]
- Added support to include additional properties in Property types [#20012]
## [v4.0.0] [r4.26.0]
- Switched JSON management to gcube-jackson [#19116]

View File

@ -10,7 +10,7 @@
<groupId>org.gcube.information-system</groupId>
<artifactId>information-system-model</artifactId>
<version>4.0.0</version>
<version>4.1.0-SNAPSHOT</version>
<name>Information System Model</name>
<description>Information System Model is the reference model of the gCube Information System</description>
<packaging>jar</packaging>

View File

@ -1,9 +1,17 @@
package org.gcube.informationsystem.base.impl.properties;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.gcube.com.fasterxml.jackson.annotation.JsonIgnore;
import org.gcube.com.fasterxml.jackson.annotation.JsonTypeName;
import org.gcube.informationsystem.base.impl.ElementImpl;
import org.gcube.informationsystem.base.reference.Element;
import org.gcube.informationsystem.base.reference.properties.PropertyElement;
import org.gcube.informationsystem.model.reference.properties.Property;
import org.gcube.informationsystem.utils.ElementMapper;
/**
* @author Luca Frosini (ISTI - CNR)
@ -16,8 +24,74 @@ public class PropertyElementImpl extends ElementImpl implements Property {
*/
private static final long serialVersionUID = 1396998430221747445L;
@JsonIgnore
protected Map<String, Object> additionalProperties;
@JsonIgnore
/**
* Used to allow to have an additional property starting with '_' or '@'
*/
protected final Set<String> allowedAdditionalKeys;
public PropertyElementImpl() {
super();
this.additionalProperties = new HashMap<>();
this.allowedAdditionalKeys = new HashSet<>();
this.allowedAdditionalKeys.add(SUPERCLASSES_PROPERTY);
}
@Override
public Map<String, Object> getAdditionalProperties() {
return additionalProperties;
}
@Override
public void setAdditionalProperties(Map<String, Object> additionalProperties) {
this.additionalProperties = additionalProperties;
}
@Override
public Object getAdditionalProperty(String key) {
return additionalProperties.get(key);
}
@Override
public void setAdditionalProperty(String key, Object value) {
if(!allowedAdditionalKeys.contains(key)){
if(key.startsWith("_")) {
return;
}
if(key.startsWith("@")) {
return;
}
}
/*
Additional properties are not deserialized to the proper property type.
The first attempt was to try to write a specific deserializer but it fails.
This fix the issue.
*/
try {
if(value instanceof Map<?,?>) {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String,Object>) value;
if(map.containsKey(Element.CLASS_PROPERTY)) {
String reserialized = ElementMapper.getObjectMapper().writeValueAsString(map);
Property property = ElementMapper.unmarshal(Property.class, reserialized);
value = property;
}
}
}catch (Throwable e) {
e.getMessage();
// Any type of error/exception must be catched
}
/* END of fix to properly deserialize Property types*/
this.additionalProperties.put(key, value);
}
public void addAllowedAdditionalKey(String allowedAdditionalKey){
this.allowedAdditionalKeys.add(allowedAdditionalKey);
}
}

View File

@ -32,6 +32,13 @@ public interface Header extends Property {
public static final String CREATION_TIME_PROPERTY = "creationTime";
public static final String LAST_UPDATE_TIME_PROPERTY = "lastUpdateTime";
/**
* Used when requested to include contexts in header.
* This is not a native property (it is just generated by server for administration clients convenience)
*/
public static final String __CONTEXTS = "contexts";
@ISProperty(name = UUID_PROPERTY, readonly = true, mandatory = true, nullable = false)
public UUID getUUID();

View File

@ -3,9 +3,16 @@
*/
package org.gcube.informationsystem.model.reference.properties;
import java.util.Map;
import org.gcube.com.fasterxml.jackson.annotation.JsonAnyGetter;
import org.gcube.com.fasterxml.jackson.annotation.JsonAnySetter;
import org.gcube.com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.gcube.com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.gcube.informationsystem.base.reference.SchemaMixedElement;
import org.gcube.informationsystem.base.reference.properties.PropertyElement;
import org.gcube.informationsystem.model.impl.properties.PropertyImpl;
import org.gcube.informationsystem.utils.AdditionalPropertiesSerializer;
/**
* @author Luca Frosini (ISTI - CNR)
@ -14,10 +21,25 @@ import org.gcube.informationsystem.model.impl.properties.PropertyImpl;
*/
// @JsonIgnoreProperties(ignoreUnknown=true)
@JsonDeserialize(as=PropertyImpl.class)
public interface Property extends PropertyElement {
public interface Property extends PropertyElement, SchemaMixedElement {
public static final String NAME = "Property"; //Property.class.getSimpleName();
public static final String DESCRIPTION = "This is the base class for Properties";
public static final String VERSION = "1.0.0";
@JsonAnyGetter
@JsonSerialize(using = AdditionalPropertiesSerializer.class)
@Override
public Map<String,Object> getAdditionalProperties();
@Override
public void setAdditionalProperties(Map<String,Object> additionalProperties);
@Override
public Object getAdditionalProperty(String key);
@JsonAnySetter
@Override
public void setAdditionalProperty(String key, Object value);
}

View File

@ -1,9 +1,13 @@
package org.gcube.informationsystem.model.impl.properties;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.gcube.com.fasterxml.jackson.core.JsonParseException;
import org.gcube.com.fasterxml.jackson.databind.JsonMappingException;
import org.gcube.informationsystem.model.reference.properties.Header;
import org.gcube.informationsystem.model.reference.properties.Property;
import org.gcube.informationsystem.utils.ElementMapper;
@ -40,5 +44,21 @@ public class HeaderTest {
Assert.assertTrue(h.getLastUpdateTime().compareTo(date)==0);
logger.debug(ElementMapper.marshal(h));
}
@Test
public void testContextsInHeader() throws JsonParseException, JsonMappingException, IOException {
String headerJson = "{\"@class\":\"Header\",\"uuid\":\"cee84aaf-030c-4170-b554-836e7df3f611\",\"creator\":\"UNKNOWN_USER\",\"modifiedBy\":null,\"creationTime\":\"2020-11-09 10:01:25.415 +0000\",\"lastUpdateTime\":\"2020-11-09 10:01:25.415 +0000\",\"contexts\":[\"167114e0-9027-4e9e-83af-57973a8f8f08\",\"bad5f350-345c-11e9-9f49-cef9b1608c3f\"]}";
Property property = ElementMapper.unmarshal(Property.class, headerJson);
logger.debug("{}", property);
Header h = ElementMapper.unmarshal(Header.class, headerJson);
logger.debug("{}", h);
@SuppressWarnings("unchecked")
List<String> contexts = (List<String>) h.getAdditionalProperty(Header.__CONTEXTS);
logger.debug("Contexts UUIDs are {}", contexts);
}
}