Skip to content

Support form creation #447

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 65 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
ac8c266
hal-forms first commit
Apr 14, 2016
47d867e
Skip warnings
gillarramendi Apr 15, 2016
287bb8d
SuggestBuilder supports value arrays
Apr 18, 2016
4d87ec4
empty constructor Form
Apr 18, 2016
d019fe4
using resolve method
Apr 18, 2016
ab44d67
Template serialization
gillarramendi Apr 18, 2016
1f6ec52
Template default constructor
Apr 18, 2016
22b2f4c
Merge branch 'master' of https://github.com/hdiv/spring-hateoas
Apr 18, 2016
8d9817b
ObjectMapper module with Templates serializer
Apr 18, 2016
5d37134
apply HalTemplateListSerializer to templates property
Apr 18, 2016
a112354
Don't create default link if self exists with same href
gillarramendi Apr 18, 2016
1611031
dont serialize default values
Apr 18, 2016
f85e837
Avoid json property duplication moving the@JsonProperty annotation t…
Apr 19, 2016
d25cbb8
Iterable replaces Collection
Apr 19, 2016
33f1366
Iterable replaces Collection
Apr 19, 2016
2b944fb
ValueSuggestSerializer
Apr 19, 2016
fd1f82c
Correct tests
Apr 19, 2016
73c688d
Serializer for direct suggest values
Apr 19, 2016
160d180
Added contentType to Template
Apr 19, 2016
31d5bcf
check null values for valueField and testField properties in suggest …
Apr 19, 2016
472de4c
test case for Template contentType
Apr 19, 2016
6fa6687
Replaced LinkBuilder by TemplateBuilder as base clase of FormBuilder
Apr 19, 2016
5066402
Added FIXME
Apr 19, 2016
2a04a28
@JsonPropertyOrder moved to Template
Apr 19, 2016
6103717
Serialization preferences
Apr 19, 2016
80126ab
Change comprobation of self link and make use of constants
Apr 19, 2016
570fbca
Integration tests of Jackson2HalFormsModule
Apr 19, 2016
2afc212
More integration tests of Jackson2HalFormsModule
Apr 19, 2016
3027831
Render suggest elements as embedded resources
gillarramendi Apr 19, 2016
0c87ddf
Move annotations of _templates and _embedded properties to getters an…
Apr 20, 2016
31a99f0
Removed HalEmbeddedResourcesSerializer
Apr 20, 2016
da3e95b
Detect curied rels in embedded suggest with EmbeddedMapper
Apr 20, 2016
c2149a9
Make public EmbeddedMapper class
Apr 20, 2016
eb828ea
Correct test case for embedded suggest
Apr 20, 2016
5c62cd4
Make use of EmbeddedWrappers for embedding suggest values
Apr 20, 2016
a1cd59b
Reduce field visibility
anderruiz Apr 21, 2016
7d0834a
Reduce field visibility and add @Override annotations
anderruiz Apr 21, 2016
020ff39
Change to make private class fields final
anderruiz Apr 21, 2016
b0744c8
Minor performance improvement and reduce variable visibility
anderruiz Apr 21, 2016
5a0be60
Mark private field as final
anderruiz Apr 21, 2016
fa3fbf4
Mark private field as final
anderruiz Apr 21, 2016
165d184
Remove public keyword from public interface methods
anderruiz Apr 21, 2016
ddc2286
Minor performance improvements and include braces in and if
anderruiz Apr 21, 2016
953710d
Override annotation for implemented methods
anderruiz Apr 21, 2016
0936733
Null check is not needed in an instanceof and mark field as final
anderruiz Apr 21, 2016
571c5b0
Null check is not needed in an instanceof, final field and compare Enum
anderruiz Apr 21, 2016
d35e3d0
mark final fields
anderruiz Apr 21, 2016
3a8a29f
Reduce field visibility and do not create an unneeded iterator
anderruiz Apr 21, 2016
8e47b5f
Prefer foreach for iterators and remove unneeded this keywords
anderruiz Apr 21, 2016
c1b7fbc
Eager EmbeddWrappers inicialization
Apr 21, 2016
fabb98a
Merge commit '8e47b5f3743bee6c014ff6e9f6dcc8dd6de466b1'
Apr 21, 2016
3c6c3ae
Removed comment: The substring begins at the specified beginIndex and…
Apr 21, 2016
b6c8633
Do not create unneded iterator
Apr 21, 2016
31029a8
Remove last comma reducing StringBuilder length
Apr 21, 2016
e83c5fb
Remove EmbeddedWrappers
Apr 21, 2016
1962e92
Refactor of SuggestBuilderFactory
Apr 21, 2016
38e9998
Add license header
gillarramendi Apr 21, 2016
0ff812a
Merge branch 'master' of github.com:hdiv/spring-hateoas into master-hdiv
gillarramendi Apr 21, 2016
a75dca4
Merge branch 'master' of https://github.com/hdiv/spring-hateoas
Apr 21, 2016
09fbae3
Tests working
gillarramendi Apr 21, 2016
50c6529
Merge branch 'master' of https://github.com/hdiv/spring-hateoas
Apr 21, 2016
dd63309
Interface for classes that contains Templates
Apr 27, 2016
dac7ff1
required attribute of Property
Apr 27, 2016
81bf71e
Allow to update the suggest's Link
Apr 27, 2016
4de2ae0
Update test for "required" Property
Apr 27, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.hateoas.forms;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
* @see Suggest
*/
@JsonInclude(Include.NON_EMPTY)
@JsonIgnoreProperties({ "type" })
public class AbstractSuggest implements Suggest {

private final String textField;

private final String valueField;

public AbstractSuggest(String textField, String valueField) {
this.textField = textField;
this.valueField = valueField;
}

@Override
@JsonProperty("value-field")
public String getValueField() {
return valueField;
}

@Override
@JsonProperty("prompt-field")
public String getTextField() {
return textField;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.hateoas.forms;

/**
* Abstract class that helps to construct {@link Suggest}
* @see PropertyBuilder
* @see TemplateBuilder
*/
public abstract class AbstractSuggestBuilder implements SuggestBuilder {

String textFieldName;

String valueFieldName;

@Override
public AbstractSuggestBuilder textField(String textFieldName) {
this.textFieldName = textFieldName;
return this;
}

@Override
public AbstractSuggestBuilder valueField(String valueFieldName) {
this.valueFieldName = valueFieldName;
return this;
}

@Override
public abstract Suggest build();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.hateoas.forms;

import org.springframework.hateoas.forms.ValueSuggest.ValueSuggestType;

/**
* Builds {@link ValueSuggest} of type {@link ValueSuggestType#EMBEDDED}
*
*/
public class EmbeddedSuggestBuilder<D> extends ValueSuggestBuilder<D> {

public EmbeddedSuggestBuilder(Iterable<D> values) {
super(values);
}

@Override
public Suggest build() {
return new ValueSuggest<D>(values, textFieldName, valueFieldName, ValueSuggestType.EMBEDDED);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.hateoas.forms;

/**
* Exception fired by {@link FieldUtils} when a class doesn't have a field of a specified name.
*
*/
public class FieldNotFoundException extends RuntimeException {

private static final long serialVersionUID = 2591233443652872298L;

private final Class<?> targetClass;

private final String field;

public FieldNotFoundException(Class<?> targetClass, String field) {
this.targetClass = targetClass;
this.field = field;
}

public Class<?> getTargetClass() {
return targetClass;
}

public String getField() {
return field;
}

}
112 changes: 112 additions & 0 deletions src/main/java/org/springframework/hateoas/forms/FieldUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright 2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.hateoas.forms;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;

import org.springframework.core.ResolvableType;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

/**
* Utility class for searching fields of a class
*
*/
public class FieldUtils {
private static final char DOT = '.';

/**
* Attempt to find the {@link Class} of the {@link Field} on the supplied class by the especified path.
*
* @param type
* @param path may be a nested path dot separated
* @return
*/
public static Class<?> findFieldClass(Class<?> type, String path) {
int firstDot = path.indexOf(DOT);
if (firstDot!=-1) {
String propertyName = path.substring(0, firstDot);
Class<?> childType = findSimpleFieldClass(type, propertyName);
if (childType == null) {
throw new FieldNotFoundException(type, propertyName);
}
return findFieldClass(childType, path.substring(firstDot + 1, path.length()));
}
else {
return findSimpleFieldClass(type, path);
}
}

/**
* Attempt to find a {@link Field} declared in a {@link Class}. In first instance tries to find the getter
* {@link Method} of supplied fieldName. If getter is not present attempts to find for declared field.
* @param type
* @param fieldName
* @return
*/
private static Class<?> findSimpleFieldClass(Class<?> type, String fieldName) {

Method method = ReflectionUtils.findMethod(type, "get" + StringUtils.capitalize(fieldName));
ResolvableType resolvableType = null;
if (null != method) {
resolvableType = ResolvableType.forMethodReturnType(method);
}
else {
try {
resolvableType = ResolvableType.forField(type.getDeclaredField(fieldName));
}
catch (SecurityException e) {
throw new FieldNotFoundException(type, fieldName);
}
catch (NoSuchFieldException e) {
throw new FieldNotFoundException(type, fieldName);
}
}

return getActualType(resolvableType);
}

/**
* Returns the {@link Class} of supplied {@link ResolvableType} considering that:
*
* <ul>
* <li>- if resolvableType is an array, the component type is returned</li>
* <li>- if resolvableType is a {@link Collection}, generic parameter class is returned</li>
* <li>- if resolvableType is a {@link Map}, {@link NotSupportedException} is returned</li>
* <li>- otherwise resolvableType raw class is returned</li>
* </ul>
*
* @param resolvableType
* @return
*/
private static Class<?> getActualType(ResolvableType resolvableType) {
if (resolvableType.isArray()) {
return resolvableType.getComponentType().resolve();
}
else if (resolvableType.asCollection() != ResolvableType.NONE) {
return resolvableType.getGeneric(0).resolve();
}
else if (resolvableType.asMap() != ResolvableType.NONE) {
throw new NotSupportedException(resolvableType.resolve() + " is not supported");
}
else {
return resolvableType.resolve();
}
}
}
49 changes: 49 additions & 0 deletions src/main/java/org/springframework/hateoas/forms/Form.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.hateoas.forms;

import org.springframework.web.bind.annotation.RequestBody;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;

/**
* HAL-FORMS {@link Template} that contains the argument marked as {@link RequestBody}
*/
@JsonIgnoreProperties({ "body", "href", "rel" })
@JsonInclude(Include.NON_EMPTY)
public class Form extends Template {

private static final long serialVersionUID = -933494757445089955L;

private Object body;

public Form() {
}

public Form(String href, String rel) {
super(href, rel);
}

public void setBody(Object body) {
this.body = body;
}

public Object getBody() {
return body;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.hateoas.forms;

import java.lang.reflect.Method;

import org.springframework.hateoas.core.DummyInvocationUtils;
import org.springframework.hateoas.mvc.ControllerFormBuilder;

public interface FormBuilderFactory<T extends TemplateBuilder> {
/**
* Returns a {@link ControllerFormBuilder} pointing to the URI mapped to the given {@link Method} and expanding this
* mapping using the given parameters.
*
* @param method must not be {@literal null}.
* @param parameters
* @return
*/
T formTo(Method method, Object... parameters);

/**
* Returns a {@link ControllerFormBuilder} pointing to the URI mapped to the given {@link Method} assuming it was
* invoked on an object of the given type.
*
* @param type must not be {@literal null}.
* @param method must not be {@literal null}.
* @param parameters
* @return
*/
T formTo(Class<?> type, Method method, Object... parameters);

/**
* Returns a {@link ControllerFormBuilder} pointing to the URI mapped to the method the result is handed into this
* method. Use {@link DummyInvocationUtils#methodOn(Class, Object...)} to obtain a dummy instance of a controller to
* record a dummy method invocation on. See {@link HalFormsLinkBuilder#linkTo(Object)} for an example.
*
* @see ControllerLinkBuilder#linkTo(Object)
* @param methodInvocationResult must not be {@literal null}.
* @return
*/
T formTo(Object methodInvocationResult);
}
Loading