#1443 - Expose affordance input media type in HAL FORMS contentType attribute.
Fixed the contentType in HalFormsTemplate to only contain a single media type. Also adapted HalFormsAffordanceModelFactory to the new API introduced for #1441.
This commit is contained in:
@@ -15,12 +15,8 @@
|
||||
*/
|
||||
package org.springframework.hateoas.mediatype.hal.forms;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.hateoas.AffordanceModel;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.QueryParameter;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.hateoas.mediatype.ConfiguredAffordance;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
/**
|
||||
@@ -31,8 +27,8 @@ import org.springframework.http.MediaType;
|
||||
*/
|
||||
class HalFormsAffordanceModel extends AffordanceModel {
|
||||
|
||||
public HalFormsAffordanceModel(String name, Link link, HttpMethod httpMethod, InputPayloadMetadata inputType,
|
||||
List<QueryParameter> queryMethodParameters, PayloadMetadata outputType) {
|
||||
super(name, link, httpMethod, inputType, queryMethodParameters, outputType);
|
||||
public HalFormsAffordanceModel(ConfiguredAffordance configured) {
|
||||
super(configured.getNameOrDefault(), configured.getTarget(), configured.getMethod(), configured.getInputMetadata(),
|
||||
configured.getQueryParameters(), configured.getOutputMetadata());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,16 +15,10 @@
|
||||
*/
|
||||
package org.springframework.hateoas.mediatype.hal.forms;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.hateoas.AffordanceModel;
|
||||
import org.springframework.hateoas.AffordanceModel.InputPayloadMetadata;
|
||||
import org.springframework.hateoas.AffordanceModel.PayloadMetadata;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.QueryParameter;
|
||||
import org.springframework.hateoas.mediatype.AffordanceModelFactory;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.hateoas.mediatype.ConfiguredAffordance;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
/**
|
||||
@@ -39,12 +33,11 @@ class HalFormsAffordanceModelFactory implements AffordanceModelFactory {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.hateoas.AffordanceModelFactory#getAffordanceModel(java.lang.String, org.springframework.hateoas.Link, org.springframework.http.HttpMethod, org.springframework.core.ResolvableType, java.util.List, org.springframework.core.ResolvableType)
|
||||
* @see org.springframework.hateoas.mediatype.AffordanceModelFactory#getAffordanceModel(org.springframework.hateoas.mediatype.ConfiguredAffordance)
|
||||
*/
|
||||
@Override
|
||||
public AffordanceModel getAffordanceModel(String name, Link link, HttpMethod httpMethod,
|
||||
InputPayloadMetadata inputType, List<QueryParameter> parameters, PayloadMetadata outputType) {
|
||||
return new HalFormsAffordanceModel(name, link, httpMethod, inputType, parameters, outputType);
|
||||
public AffordanceModel getAffordanceModel(ConfiguredAffordance configured) {
|
||||
return new HalFormsAffordanceModel(configured);
|
||||
}
|
||||
|
||||
public MediaType getMediaType() {
|
||||
|
||||
@@ -21,12 +21,10 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.hateoas.mediatype.hal.forms.HalFormsDeserializers.MediaTypesDeserializer;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
|
||||
@@ -34,7 +32,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
|
||||
/**
|
||||
* Value object for a HAL-FORMS template. Describes the available state transition details.
|
||||
@@ -53,21 +50,21 @@ final class HalFormsTemplate {
|
||||
private String title;
|
||||
private HttpMethod httpMethod;
|
||||
private List<HalFormsProperty> properties;
|
||||
private List<MediaType> contentTypes;
|
||||
private MediaType contentType;
|
||||
private String target;
|
||||
|
||||
@SuppressWarnings("null")
|
||||
private HalFormsTemplate() {
|
||||
this(null, null, Collections.emptyList(), Collections.emptyList(), null);
|
||||
this(null, null, Collections.emptyList(), null, null);
|
||||
}
|
||||
|
||||
private HalFormsTemplate(String title, HttpMethod httpMethod, List<HalFormsProperty> properties,
|
||||
List<MediaType> contentTypes, String target) {
|
||||
@Nullable MediaType contentType, String target) {
|
||||
|
||||
this.title = title;
|
||||
this.httpMethod = httpMethod;
|
||||
this.properties = properties;
|
||||
this.contentTypes = contentTypes;
|
||||
this.contentType = contentType;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@@ -78,13 +75,13 @@ final class HalFormsTemplate {
|
||||
HalFormsTemplate withTitle(String title) {
|
||||
|
||||
return this.title == title ? this
|
||||
: new HalFormsTemplate(title, this.httpMethod, this.properties, this.contentTypes, this.target);
|
||||
: new HalFormsTemplate(title, this.httpMethod, this.properties, this.contentType, this.target);
|
||||
}
|
||||
|
||||
private HalFormsTemplate withHttpMethod(HttpMethod httpMethod) {
|
||||
|
||||
return this.httpMethod == httpMethod ? this
|
||||
: new HalFormsTemplate(this.title, httpMethod, this.properties, this.contentTypes, this.target);
|
||||
: new HalFormsTemplate(this.title, httpMethod, this.properties, this.contentType, this.target);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,53 +97,35 @@ final class HalFormsTemplate {
|
||||
List<HalFormsProperty> properties = new ArrayList<>(this.properties);
|
||||
properties.add(property);
|
||||
|
||||
return new HalFormsTemplate(title, httpMethod, properties, contentTypes, target);
|
||||
return new HalFormsTemplate(title, httpMethod, properties, contentType, target);
|
||||
}
|
||||
|
||||
HalFormsTemplate withProperties(List<HalFormsProperty> properties) {
|
||||
|
||||
return this.properties == properties ? this
|
||||
: new HalFormsTemplate(title, httpMethod, properties, contentTypes, target);
|
||||
: new HalFormsTemplate(title, httpMethod, properties, contentType, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link HalFormsTemplate} with the given {@link MediaType} added as content type.
|
||||
*
|
||||
* @param mediaType must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
HalFormsTemplate andContentType(MediaType mediaType) {
|
||||
HalFormsTemplate withContentType(@Nullable MediaType contentType) {
|
||||
|
||||
Assert.notNull(mediaType, "Media type must not be null!");
|
||||
|
||||
List<MediaType> contentTypes = new ArrayList<>(this.contentTypes);
|
||||
contentTypes.add(mediaType);
|
||||
|
||||
return new HalFormsTemplate(title, httpMethod, properties, contentTypes, target);
|
||||
}
|
||||
|
||||
HalFormsTemplate withContentTypes(List<MediaType> contentTypes) {
|
||||
|
||||
return this.contentTypes == contentTypes ? this
|
||||
: new HalFormsTemplate(title, httpMethod, properties, contentTypes, target);
|
||||
return this.contentType == contentType ? this
|
||||
: new HalFormsTemplate(title, httpMethod, properties, contentType, target);
|
||||
}
|
||||
|
||||
HalFormsTemplate withTarget(String target) {
|
||||
|
||||
return this.target == target ? this
|
||||
: new HalFormsTemplate(title, httpMethod, properties, contentTypes, target);
|
||||
: new HalFormsTemplate(title, httpMethod, properties, contentType, target);
|
||||
}
|
||||
|
||||
// Jackson helper methods to create the right representation format
|
||||
|
||||
@Nullable
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
String getContentType() {
|
||||
return StringUtils.collectionToDelimitedString(contentTypes, ", ");
|
||||
return contentType == null ? null : contentType.toString();
|
||||
}
|
||||
|
||||
@JsonDeserialize(using = MediaTypesDeserializer.class)
|
||||
void setContentType(List<MediaType> mediaTypes) {
|
||||
this.contentTypes = mediaTypes;
|
||||
void setContentType(MediaType mediaType) {
|
||||
this.contentType = mediaType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -173,10 +152,6 @@ final class HalFormsTemplate {
|
||||
return this.properties;
|
||||
}
|
||||
|
||||
List<MediaType> getContentTypes() {
|
||||
return this.contentTypes;
|
||||
}
|
||||
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
String getTitle() {
|
||||
return this.title;
|
||||
@@ -207,7 +182,7 @@ final class HalFormsTemplate {
|
||||
return Objects.equals(this.title, that.title) //
|
||||
&& this.httpMethod == that.httpMethod //
|
||||
&& Objects.equals(this.properties, that.properties) //
|
||||
&& Objects.equals(this.contentTypes, that.contentTypes);
|
||||
&& Objects.equals(this.contentType, that.contentType);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -216,7 +191,7 @@ final class HalFormsTemplate {
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.title, this.httpMethod, this.properties, this.contentTypes);
|
||||
return Objects.hash(this.title, this.httpMethod, this.properties, this.contentType);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -226,6 +201,6 @@ final class HalFormsTemplate {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HalFormsTemplate(title=" + this.title + ", httpMethod=" + this.httpMethod + ", properties="
|
||||
+ this.properties + ", contentTypes=" + this.contentTypes + ")";
|
||||
+ this.properties + ", contentTypes=" + this.contentType + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,8 @@ class HalFormsTemplateBuilder {
|
||||
.forEach(it -> {
|
||||
|
||||
HalFormsTemplate template = HalFormsTemplate.forMethod(it.getHttpMethod()) //
|
||||
.withProperties(factory.createProperties(it));
|
||||
.withProperties(factory.createProperties(it))
|
||||
.withContentType(it.getInput().getPrimaryMediaType());
|
||||
|
||||
String target = it.getLink().getHref();
|
||||
|
||||
@@ -80,7 +81,6 @@ class HalFormsTemplateBuilder {
|
||||
});
|
||||
|
||||
return templates;
|
||||
|
||||
}
|
||||
|
||||
private HalFormsTemplate applyTo(HalFormsTemplate template, HalFormsTemplateBuilder.TemplateTitle templateTitle) {
|
||||
|
||||
@@ -111,7 +111,7 @@ class HalFormsMessageConverterUnitTest {
|
||||
|
||||
HalFormsTemplate template = HalFormsTemplate.forMethod(HttpMethod.GET) //
|
||||
.withTitle("HAL-FORMS unit test") //
|
||||
.andContentType(MediaTypes.HAL_JSON) //
|
||||
.withContentType(MediaTypes.HAL_JSON) //
|
||||
.andProperty(property); //
|
||||
|
||||
HalFormsDocument expected = HalFormsDocument.empty() //
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.hateoas.RepresentationModel;
|
||||
import org.springframework.hateoas.mediatype.Affordances;
|
||||
import org.springframework.hateoas.mediatype.MessageResolver;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
/**
|
||||
* @author Oliver Drotbohm
|
||||
@@ -131,6 +132,24 @@ class HalFormsTemplateBuilderUnitTest {
|
||||
assertThat(templates.get("default").getTarget()).isEqualTo("/example");
|
||||
}
|
||||
|
||||
@Test // #1443
|
||||
void exposesInputMediaTypeAsContentType() {
|
||||
|
||||
MediaType mediaType = MediaType.parseMediaType("text/uri-list");
|
||||
|
||||
Link link = Affordances.of(Link.of("/example", LinkRelation.of("create"))) //
|
||||
.afford(HttpMethod.POST) //
|
||||
.withInput(Payload.class) //
|
||||
.withInputMediaType(mediaType) //
|
||||
.withName("create") //
|
||||
.toLink();
|
||||
|
||||
Map<String, HalFormsTemplate> templates = new HalFormsTemplateBuilder(new HalFormsConfiguration(),
|
||||
MessageResolver.DEFAULTS_ONLY).findTemplates(new RepresentationModel<>().add(link));
|
||||
|
||||
assertThat(templates.get("default").getContentType()).isEqualTo(mediaType.toString());
|
||||
}
|
||||
|
||||
@Getter
|
||||
static class PatternExample extends RepresentationModel<PatternExample> {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user