DATAREST-531 - JSON Schema now exposes read-only fields.

Properties considered read-only are now explicitly marked as such in the JSON Schema output we render.

Related tickets: DATAREST-530.
This commit is contained in:
Oliver Gierke
2015-05-07 14:23:11 +02:00
parent 9cc609af97
commit f05a6baf11
4 changed files with 40 additions and 16 deletions

View File

@@ -65,7 +65,8 @@ public class JsonSchema {
* @param properties must not be {@literal null}.
* @param descriptors must not be {@literal null}.
*/
public JsonSchema(String title, String description, Collection<JsonSchemaProperty> properties, Descriptors descriptors) {
public JsonSchema(String title, String description, Collection<JsonSchemaProperty<?>> properties,
Descriptors descriptors) {
Assert.hasText(title, "Title must not be null or empty!");
Assert.notNull(properties, "JsonSchemaProperties must not be null!");
@@ -174,7 +175,7 @@ public class JsonSchema {
* @param type must not be {@literal null}.
* @param properties must not be {@literal null}.
*/
public Item(TypeInformation<?> type, Collection<JsonSchemaProperty> properties) {
public Item(TypeInformation<?> type, Collection<JsonSchemaProperty<?>> properties) {
this.type = toJsonSchemaType(type);
this.properties = new PropertiesContainer(properties);
@@ -199,7 +200,7 @@ public class JsonSchema {
@JsonInclude(Include.NON_EMPTY)
static class PropertiesContainer {
public final Map<String, JsonSchemaProperty> properties;
public final Map<String, JsonSchemaProperty<?>> properties;
public final Collection<String> requiredProperties;
/**
@@ -207,14 +208,14 @@ public class JsonSchema {
*
* @param properties must not be {@literal null}.
*/
public PropertiesContainer(Collection<JsonSchemaProperty> properties) {
public PropertiesContainer(Collection<JsonSchemaProperty<?>> properties) {
Assert.notNull(properties, "JsonSchemaPropertys must not be null!");
this.properties = new HashMap<String, JsonSchema.JsonSchemaProperty>();
this.properties = new HashMap<String, JsonSchema.JsonSchemaProperty<?>>();
this.requiredProperties = new ArrayList<String>();
for (JsonSchemaProperty property : properties) {
for (JsonSchemaProperty<?> property : properties) {
this.properties.put(property.getName(), property);
if (property.isRequired()) {
@@ -272,14 +273,18 @@ public class JsonSchema {
* @since 2.3
*/
@JsonInclude(Include.NON_EMPTY)
abstract static class JsonSchemaProperty {
abstract static class JsonSchemaProperty<T extends JsonSchemaProperty<T>> {
private final String name;
private final boolean required;
private boolean readOnly;
protected JsonSchemaProperty(String name, boolean required) {
this.name = name;
this.required = required;
this.readOnly = false;
}
@JsonIgnore
@@ -290,6 +295,16 @@ public class JsonSchema {
private boolean isRequired() {
return required;
}
public boolean isReadOnly() {
return readOnly;
}
@SuppressWarnings("unchecked")
protected T withReadOnly() {
this.readOnly = true;
return (T) this;
}
}
/**
@@ -298,7 +313,7 @@ public class JsonSchema {
* @author Oliver Gierke
* @since 2.3
*/
static class Property extends JsonSchemaProperty {
static class Property extends JsonSchemaProperty<Property> {
private static final TypeInformation<?> STRING_TYPE_INFORMATION = ClassTypeInformation.from(String.class);

View File

@@ -140,13 +140,13 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
final ResourceMetadata metadata = mappings.getMappingFor(persistentEntity.getType());
Descriptors descriptors = new Descriptors();
List<JsonSchemaProperty> propertiesFor = getPropertiesFor(persistentEntity.getType(), metadata, descriptors);
List<JsonSchemaProperty<?>> propertiesFor = getPropertiesFor(persistentEntity.getType(), metadata, descriptors);
return new JsonSchema(persistentEntity.getName(), resolveMessage(metadata.getItemResourceDescription()),
propertiesFor, descriptors);
}
private List<JsonSchemaProperty> getPropertiesFor(Class<?> type, final ResourceMetadata metadata,
private List<JsonSchemaProperty<?>> getPropertiesFor(Class<?> type, final ResourceMetadata metadata,
final Descriptors descriptors) {
final PersistentEntity<?, ?> entity = entities.getPersistentEntity(type);
@@ -154,10 +154,10 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
final AssociationLinks associationLinks = new AssociationLinks(mappings);
if (entity == null) {
return Collections.<JsonSchemaProperty> emptyList();
return Collections.<JsonSchemaProperty<?>> emptyList();
}
final List<JsonSchemaProperty> properties = new ArrayList<JsonSchema.JsonSchemaProperty>();
final List<JsonSchemaProperty<?>> properties = new ArrayList<JsonSchema.JsonSchemaProperty<?>>();
for (BeanPropertyDefinition definition : jackson) {
@@ -171,6 +171,10 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
: getDescriptionFor(persistentProperty, metadata);
Property property = getSchemaProperty(definition, propertyType, description);
if (persistentProperty != null && !persistentProperty.isWritable()) {
property = property.withReadOnly();
}
if (format != null) {
// Types with explicitly registered format -> value object with format
@@ -222,7 +226,8 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
return properties;
}
private Collection<JsonSchemaProperty> getNestedPropertiesFor(PersistentProperty<?> property, Descriptors descriptors) {
private Collection<JsonSchemaProperty<?>> getNestedPropertiesFor(PersistentProperty<?> property,
Descriptors descriptors) {
if (!property.isEntity()) {
return Collections.emptyList();

View File

@@ -124,6 +124,9 @@ public class PersistentEntityToJsonSchemaConverterUnitTests {
constraints.add(new Constraint("$.properties.shippingAddresses.items['$ref']", is("#/descriptors/address"),
"References descriptor of complex element type."));
// DATAREST-531
constraints.add(new Constraint("$.properties.email.readOnly", is(true), "Email is read-only property"));
assertConstraints(User.class, constraints);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013 the original author or authors.
* Copyright 2013-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import org.springframework.data.annotation.ReadOnlyProperty;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
@@ -41,7 +42,7 @@ public class User {
public Set<Address> shippingAddresses;
public List<String> nicknames;
public Gender gender;
public EmailAddress email;
public @ReadOnlyProperty EmailAddress email;
public LocalDateTime java8DateTime;
public org.joda.time.LocalDateTime jodaDateTime;
public TypeWithPattern pattern;
@@ -57,8 +58,8 @@ public class User {
public EmailAddress(String value) {
this.value = value;
}
@Override
@Override
@JsonValue
public String toString() {
return value;