Skip to content

Commit

Permalink
DATAREST-665 - Switched to a more consistent scheme for I18N of JsonS…
Browse files Browse the repository at this point in the history
…chema.

We now use the following keys in the resource bundle to determine values for the title attribute of JSON schema property (in descending order of preference):

$fullyQualifiedClassName.$property._title
$simpleClassName.$property._title
$property._title

Also tweaked JsonProperty.format to make sure it always serializes as its toString() value.
  • Loading branch information
odrotbohm committed Sep 2, 2015
1 parent 191f4b6 commit b4bbc1d
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 8 deletions.
Expand Up @@ -38,6 +38,8 @@
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;

/**
* Model class to render JSON schema documents.
Expand Down Expand Up @@ -326,7 +328,7 @@ public static class JsonSchemaProperty extends AbstractJsonSchemaProperty<JsonSc

public String description;
public String type;
public JsonSchemaFormat format;
public @JsonSerialize(using = ToStringSerializer.class) JsonSchemaFormat format;
public String pattern;
public Boolean uniqueItems;
public @JsonProperty("$ref") String reference;
Expand Down
Expand Up @@ -25,6 +25,7 @@
import java.util.Set;
import java.util.regex.Pattern;

import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
Expand All @@ -40,7 +41,6 @@
import org.springframework.data.rest.core.mapping.ResourceMapping;
import org.springframework.data.rest.core.mapping.ResourceMappings;
import org.springframework.data.rest.core.mapping.ResourceMetadata;
import org.springframework.data.rest.core.mapping.SimpleResourceDescription;
import org.springframework.data.rest.webmvc.json.JsonSchema.AbstractJsonSchemaProperty;
import org.springframework.data.rest.webmvc.json.JsonSchema.Definitions;
import org.springframework.data.rest.webmvc.json.JsonSchema.EnumProperty;
Expand Down Expand Up @@ -148,8 +148,7 @@ public JsonSchema convert(Object source, TypeDescriptor sourceType, TypeDescript
List<AbstractJsonSchemaProperty<?>> propertiesFor = getPropertiesFor(persistentEntity.getType(), metadata,
descriptors);

String title = resolveMessageWithDefault(new DefaultMessageSourceResolvable(
SimpleResourceDescription.DEFAULT_KEY_PREFIX.concat(".").concat(persistentEntity.getType().getSimpleName())));
String title = resolveMessageWithDefault(new ResolvableType(persistentEntity.getType()));

return new JsonSchema(title, resolveMessage(metadata.getItemResourceDescription()), propertiesFor, descriptors);
}
Expand Down Expand Up @@ -261,13 +260,11 @@ private Collection<AbstractJsonSchemaProperty<?>> getNestedPropertiesFor(Persist
return getPropertiesFor(property.getActualType(), mappings.getMetadataFor(property.getActualType()), descriptors);
}

@SuppressWarnings("unchecked")
private JsonSchemaProperty getSchemaProperty(BeanPropertyDefinition definition, TypeInformation<?> type,
ResourceDescription description) {

String name = definition.getName();
String title = resolveMessageWithDefault(
new DefaultMessageSourceResolvable(description.getMessage().concat("._title")));
String title = resolveMessageWithDefault(new ResolvableProperty(definition));
String resolvedDescription = resolveMessage(description);
boolean required = definition.isRequired();
Class<?> rawType = type.getType();
Expand Down Expand Up @@ -417,4 +414,64 @@ public String getDefaultMessage() {
.collectionToDelimitedString(Arrays.asList(SPLIT_CAMEL_CASE.split(tail)), " ").toLowerCase(Locale.US));
}
}

/**
* A {@link BeanPropertyDefinition} that can be resolved via a {@link MessageSource}.
*
* @author Oliver Gierke
* @since 2.4.1
*/
private static class ResolvableProperty extends DefaultMessageSourceResolvable {

private static final long serialVersionUID = -5603381674553244480L;

/**
* Creates a new {@link ResolvableProperty} for the given {@link BeanPropertyDefinition}.
*
* @param property must not be {@literal null}.
*/
public ResolvableProperty(BeanPropertyDefinition property) {
super(getCodes(property));
}

private static String[] getCodes(BeanPropertyDefinition property) {

Assert.notNull(property, "BeanPropertyDefinition must not be null!");

Class<?> owner = property.getPrimaryMember().getDeclaringClass();

String propertyTitle = property.getInternalName().concat("._title");
String localName = owner.getSimpleName().concat(".").concat(propertyTitle);
String fullName = owner.getName().concat(".").concat(propertyTitle);

return new String[] { fullName, localName, propertyTitle };
}
}

/**
* A type whose title can be resolved through a {@link MessageSource}.
*
* @author Oliver Gierke
* @since 2.4.1
*/
private static class ResolvableType extends DefaultMessageSourceResolvable {

private static final long serialVersionUID = -7199875272753949857L;

/**
* Creates a new {@link ResolvableType} for the given type.
*
* @param type must not be {@literal null}.
*/
public ResolvableType(Class<?> type) {
super(getTitleCodes(type));
}

private static String[] getTitleCodes(Class<?> type) {

Assert.notNull(type, "Type must not be null!");

return new String[] { type.getName().concat("._title"), type.getSimpleName().concat("._title") };
}
}
}
Expand Up @@ -146,6 +146,12 @@ public void fulfillsConstraintsForUser() throws Exception {
constraints.add(new Constraint("$.properties.shippingAddresses.title", is("Shipping addresses"),
"Defaults titles correctly (split at camel case)"));

// DATAREST-665
constraints.add(new Constraint("$.properties.address.title", is("Adresse"), "I18n from simple property"));
constraints.add(new Constraint("$.properties.gender.title", is("Geschlecht"), "I18n from property on local type"));
constraints.add(
new Constraint("$.properties.firstname.title", is("Vorname"), "I18n from property on fully-qualified type"));

assertConstraints(User.class, constraints);
}

Expand Down
@@ -1 +1,14 @@
rest.description.profile=Profile description
rest.description.profile=Profile description

# User
# Local property
address._title=Adresse

# Property on simple type
User.gender._title=Geschlecht

# Property on fully-qualified property
org.springframework.data.rest.webmvc.mongodb.User.firstname._title=Vorname

# Local property that should be trumped by the more precise definition above
firstname._title=emanroV

0 comments on commit b4bbc1d

Please sign in to comment.