Skip to content
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

Use latest release of Spring and Spring HATEOAS #42

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 13 additions & 13 deletions README.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,10 @@ Look into the https://github.com/dschulten/hydra-java/blob/master/hydra-sample/s
The tests in https://github.com/dschulten/hydra-java/blob/master/hydra-jsonld/src/test/java/de/escalon/hypermedia/hydra/serialize/JacksonHydraSerializerTest.java[JacksonHydraSerializerTest] demonstrate the usage of `@Vocab`, `@Expose` and `@Term`.

== Features of hydra-spring
The conversion of a spring-hateoas Resource to hydra does the following:
The conversion of a spring-hateoas EntityModel to hydra does the following:

- renders a spring-hateoas `List<Link>` in a `Resource<T>` in json-ld style
- renders spring-hateoas `Resources<T>` as `hydra:Collection`. If you use this feature, make sure you have a `@Term(define = "hydra", as = "http://www.w3.org/ns/hydra/core#")` annotation in your context.
- renders a spring-hateoas `List<Link>` in a `EntityModel<T>` in json-ld style
- renders spring-hateoas `CollectionModel<T>` as `hydra:Collection`. If you use this feature, make sure you have a `@Term(define = "hydra", as = "http://www.w3.org/ns/hydra/core#")` annotation in your context.
- renders spring-hateoas `PagedResources<T>` as `hydra:Collection` with a `hydra:PartialCollectionView`. If you use this feature, make sure you have a `@Term(define = "hydra", as = "http://www.w3.org/ns/hydra/core#")` annotation in your context.
- renders response with `"@vocab" : "http://schema.org/"` by default, a different `@vocab` can be defined on a class or package using the `@Vocab` annotation.
- supports vocabularies in addition to the default vocabulary via terms in the `@context`. Use `@Term` in conjunction with `@Terms` on a class or package for this.
Expand Down Expand Up @@ -219,7 +219,7 @@ AffordanceBuilder.linkTo(methodOn(Foo.class).getBars()).rel("bars") // rel() ins


In the following we use `AffordanceBuilder` to add a `self` rel that can be used with GET, PUT and DELETE to an event bean.
First we wrap the event into a `Resource` so we can add affordances to it. Then we use the `linkTo-methodOn` technique three times to describe that the self rel can be used to get, update and delete the event.
First we wrap the event into a `EntityModel` so we can add affordances to it. Then we use the `linkTo-methodOn` technique three times to describe that the self rel can be used to get, update and delete the event.

[source, Java]
----
Expand All @@ -232,9 +232,9 @@ First we wrap the event into a `Resource` so we can add affordances to it. Then
public class EventController {

@RequestMapping(value = "/{eventId}", method = RequestMethod.GET)
public @ResponseBody Resource<Event> getEvent(@PathVariable Integer eventId) {
public @ResponseBody EntityModel<Event> getEvent(@PathVariable Integer eventId) {
// get the event from some backend, then:
Resource<Event> eventResource = new Resource<Event>(event);
EntityModel<Event> eventResource = new EntityModel<Event>(event);

// using AffordanceBuilder.linkTo and AffordanceBuilder.methodOn
// instead of ControllerLinkBuilder methods
Expand All @@ -249,7 +249,7 @@ First we wrap the event into a `Resource` so we can add affordances to it. Then
}

@RequestMapping(value = "/{eventId}", method = RequestMethod.GET)
public @ResponseBody Resource<Event> getEvent(@PathVariable Integer eventId) {
public @ResponseBody EntityModel<Event> getEvent(@PathVariable Integer eventId) {
...
}

Expand Down Expand Up @@ -328,27 +328,27 @@ When rendered with the `HydraMessageConverter`, the resulting json-ld event obje

=== Specifying Property Value Requirements (from V. 0.2.0)

Now let us tell the client a range of possible values for a property. We want to allow clients to add reviews for the work performed at an event. For this, we add a `Resource<CreativeWork>` to the `Event`, so that we can define an affordance on the creative work which allows clients to send reviews.
Now let us tell the client a range of possible values for a property. We want to allow clients to add reviews for the work performed at an event. For this, we add a `EntityModel<CreativeWork>` to the `Event`, so that we can define an affordance on the creative work which allows clients to send reviews.

[source, Java]
----
public class Event {
...
private final Resource<CreativeWork> workPerformed;
private final EntityModel<CreativeWork> workPerformed;

public Resource<CreativeWork> getWorkPerformed() {
public EntityModel<CreativeWork> getWorkPerformed() {
return workPerformed;
}
...
}

// in EventController:
@RequestMapping(value = "/{eventId}", method = RequestMethod.GET)
public @ResponseBody Resource<Event> getEvent(@PathVariable Integer eventId) {
public @ResponseBody EntityModel<Event> getEvent(@PathVariable Integer eventId) {

// with an event from backend do this:

event.getWorkPerformed() // <-- must be a Resource<CreativeWork>
event.getWorkPerformed() // <-- must be a EntityModel<CreativeWork>
.add(linkTo(methodOn(ReviewController.class) // <-- must use AffordanceBuilder.linkTo here
.addReview(event.id, new Review(null, new Rating(3)))) // <-- default ratingValue 3
.withRel("review"));
Expand Down Expand Up @@ -538,7 +538,7 @@ The `SirenMessageConverter` renders Spring Hateoas Responses as https://github.c
* in order to produce more expressive Siren actions, use the `linkTo-methodOn` idiom of `AffordanceBuilder` to point to your methods, as shown above for the sample `EventController` in the section AffordanceBuilder.
* possible values found by `AffordanceBuilder` are treated as checkbox or radio button fields, following the technique discussed in the https://groups.google.com/forum/#!topic/siren-hypermedia/8mbOX44gguU[Siren group].
* field types can be defined via the value of the `@Input` annotation on method parameters (e.g. `@Input(Type.DATE)`).
* nested `Resource` objects are shown as embedded representations
* nested `EntityModel` objects are shown as embedded representations
* distinguishes navigational and embedded links by a default list of navigational rels. This list can be customized via `SirenMessageConverter.addNavigationalRels`.
* for sub-entities the property name is used as relation name. The Siren class name is derived from the Java class name. The rel names can be customized using a `DocumentationProvider` implementation, e.g. the `JsonLdDocumentationProvider` from hydra-jsonld will make use of `@Expose` and `@Vocab` annotations on your response bean packages.
* relies on `XhtmlMessageConverter` to process incoming form-urlencoded requests and on `MappingJackson2HttpMessageConverter` for json requests.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ protected void serializeType(Object bean, JsonGenerator jgen, SerializerProvider
}
// adds @type attribute, reflecting the simple name of the class or the exposed annotation on the class.
final Expose classExpose = findAnnotation(bean.getClass(), Expose.class);
// TODO allow to search up the hierarchy for ResourceSupport mixins and cache found result?
// TODO allow to search up the hierarchy for RepresentationModel mixins and cache found result?
final Class<?> mixin = provider.getConfig()
.findMixInClassFor(bean.getClass());
final Expose mixinExpose = findAnnotation(mixin, Expose.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@ public class LdContextFactory {
/**
* Gets vocab for given bean.
*
* @param bean
* to inspect for vocab
* @param mixInClass
* for bean which might define a vocab or has a context provider
* @param mixinSource to inspect from
* @param bean to inspect for vocab
* @param mixInClass for bean which might define a vocab or has a context provider
* @return explicitly defined vocab or http://schema.org
*/
public String getVocab(MixinSource mixinSource, Object bean, Class<?> mixInClass) {
Expand Down Expand Up @@ -74,7 +73,7 @@ public Map<String, Object> getTerms(MixinSource mixinSource, Object bean, Class<
bean = proxyUnwrapper.unwrapProxy(bean);
}

Map<String, Object> termsMap = new LinkedHashMap<String, Object>();
Map<String, Object> termsMap = new LinkedHashMap<>();
if (bean != null) {
final Class<?> beanClass = bean.getClass();
termsMap.putAll(termsFromClass(beanClass));
Expand Down Expand Up @@ -140,7 +139,7 @@ private boolean returnsEnumCollection( Method method ) {
ParameterizedType pt = (ParameterizedType) t;
if ( pt.getActualTypeArguments().length == 1 ) {
Type arg = pt.getActualTypeArguments()[0];
return Class.class.isInstance( arg ) && Enum.class.isAssignableFrom( (Class) arg );
return arg instanceof Class && Enum.class.isAssignableFrom( (Class) arg);
}
}
}
Expand All @@ -164,7 +163,7 @@ private Map<String, Object> getAnnotatedTerms(AnnotatedElement annotatedElement,
if (annotatedTerms != null && annotatedTerm != null) {
throw new IllegalStateException("found both @Terms and @Term in " + name + ", use either one or the other");
}
Map<String, Object> annotatedTermsMap = new LinkedHashMap<String, Object>();
Map<String, Object> annotatedTermsMap = new LinkedHashMap<>();
if (annotatedTerms != null) {
final Term[] terms = annotatedTerms.value();
for (Term term : terms) {
Expand All @@ -186,17 +185,17 @@ private void collectTerms(String name, Map<String, Object> annotatedTermsMap, Te
if (!reverse) {
annotatedTermsMap.put(define, as);
} else {
Map<String, String> reverseTerm = new LinkedHashMap<String, String>();
Map<String, String> reverseTerm = new LinkedHashMap<>();
reverseTerm.put(JsonLdKeywords.AT_REVERSE, as);
annotatedTermsMap.put(define, reverseTerm);
}
}

private Object getNestedContextProviderFromMixin(MixinSource mixinSource, Object bean, Class<?> mixinClass) {
// TODO does not consider Collection<Resource> or Collection<PersistentEntityResource> to find mixin of
// TODO does not consider Collection<EntityModel> or Collection<PersistentEntityResource> to find mixin of
// object wrapped in resource
// TODO does not consider package of object wrapped in resource
// TODO: we do not know Resources here
// TODO: we do not know CollectionModel here
if (mixinClass == null) {
return null;
}
Expand Down Expand Up @@ -256,7 +255,7 @@ private Method getContextProvider(Class<?> beanClass) {
private void addEnumTerms(Map<String, Object> termsMap, Expose expose, String name,
Enum value) throws NoSuchFieldException {
if (value != null) {
Map<String, String> map = new LinkedHashMap<String, String>();
Map<String, String> map = new LinkedHashMap<>();
if (expose != null) {
map.put(JsonLdKeywords.AT_ID, expose.value());
}
Expand All @@ -269,7 +268,7 @@ private void addEnumTerms(Map<String, Object> termsMap, Expose expose, String na
termsMap.put(value.toString(), enumValueExpose.value());
} else {
// might use upperToCamelCase if nothing is exposed
final String camelCaseEnumValue = WordUtils.capitalizeFully(value.toString(), new char[]{'_'})
final String camelCaseEnumValue = WordUtils.capitalizeFully(value.toString(), '_')
.replaceAll("_", "");
termsMap.put(value.toString(), camelCaseEnumValue);
}
Expand Down
3 changes: 0 additions & 3 deletions hydra-sample/service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,15 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<!--<version>3.2.9.RELEASE</version>-->
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
<!--version>1.1.0.RELEASE</version-->
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
Expand Down
Loading