DS-3533 Drop embed/linkOptional properties from LinkRest

This commit is contained in:
Chris Wilper
2020-02-04 13:36:32 -05:00
parent 169cd502a2
commit 7d3885f939
15 changed files with 39 additions and 111 deletions

View File

@@ -64,17 +64,12 @@ public class DSpaceResourceHalLinkFactory extends HalLinkFactory<DSpaceResource,
.linkToSingleResource((RestAddressableModel) linkedObject, name); .linkToSingleResource((RestAddressableModel) linkedObject, name);
} }
if (linkedObject != null || !linkRest.linkOptional() || !linkRest.embedOptional()) { if (!halResource.getContent().getProjection().allowLinking(halResource, linkRest)) {
if (linkRest.linkOptional() && linkRest.embedOptional()
&& !halResource.getContent().getProjection()
.allowLinking(halResource, linkRest)) {
continue; // projection disallows this optional method-level link continue; // projection disallows this optional method-level link
} }
halResource.add(linkToSubResource); halResource.add(linkToSubResource);
} }
}
} else if (RestModel.class.isAssignableFrom(readMethod.getReturnType())) { } else if (RestModel.class.isAssignableFrom(readMethod.getReturnType())) {
Link linkToSubResource = utils.linkToSubResource(data, name); Link linkToSubResource = utils.linkToSubResource(data, name);

View File

@@ -56,7 +56,7 @@ public class AuthenticationStatusRest extends BaseObjectRest<Integer> {
} }
} }
@LinkRest(linkClass = EPersonRest.class, name = "eperson", linkOptional = true) @LinkRest(linkClass = EPersonRest.class, name = "eperson")
@JsonIgnore @JsonIgnore
public EPersonRest getEPersonRest() { public EPersonRest getEPersonRest() {
return ePersonRest; return ePersonRest;

View File

@@ -17,16 +17,12 @@ import org.dspace.app.rest.RestResourceController;
@LinksRest(links = { @LinksRest(links = {
@LinkRest(name = AuthorityRest.ENTRIES, @LinkRest(name = AuthorityRest.ENTRIES,
linkClass = AuthorityEntryRest.class, linkClass = AuthorityEntryRest.class,
method = "query", method = "query"
embedOptional = true,
linkOptional = true
), ),
@LinkRest( @LinkRest(
name = AuthorityRest.ENTRY, name = AuthorityRest.ENTRY,
linkClass = AuthorityEntryRest.class, linkClass = AuthorityEntryRest.class,
method = "getResource", method = "getResource"
embedOptional = true,
linkOptional = true
) )
}) })
public class AuthorityRest extends BaseObjectRest<String> { public class AuthorityRest extends BaseObjectRest<String> {

View File

@@ -19,14 +19,12 @@ import com.fasterxml.jackson.annotation.JsonProperty.Access;
@LinkRest( @LinkRest(
name = BitstreamRest.BUNDLE, name = BitstreamRest.BUNDLE,
linkClass = BundleRest.class, linkClass = BundleRest.class,
method = "getBundle", method = "getBundle"
embedOptional = true
), ),
@LinkRest( @LinkRest(
name = BitstreamRest.FORMAT, name = BitstreamRest.FORMAT,
linkClass = BitstreamFormatRest.class, linkClass = BitstreamFormatRest.class,
method = "getFormat", method = "getFormat"
embedOptional = true
) )
}) })
public class BitstreamRest extends DSpaceObjectRest { public class BitstreamRest extends DSpaceObjectRest {

View File

@@ -22,15 +22,12 @@ import org.dspace.app.rest.RestResourceController;
@LinkRest( @LinkRest(
name = BrowseIndexRest.ITEMS, name = BrowseIndexRest.ITEMS,
linkClass = ItemRest.class, linkClass = ItemRest.class,
method = "listBrowseItems", method = "listBrowseItems"
embedOptional = true
), ),
@LinkRest( @LinkRest(
name = BrowseIndexRest.ENTRIES, name = BrowseIndexRest.ENTRIES,
linkClass = BrowseEntryRest.class, linkClass = BrowseEntryRest.class,
method = "listBrowseEntries", method = "listBrowseEntries"
embedOptional = true,
linkOptional = true
) )
}) })
public class BrowseIndexRest extends BaseObjectRest<String> { public class BrowseIndexRest extends BaseObjectRest<String> {

View File

@@ -19,14 +19,12 @@ import com.fasterxml.jackson.annotation.JsonProperty;
@LinkRest( @LinkRest(
name = BundleRest.BITSTREAMS, name = BundleRest.BITSTREAMS,
linkClass = BitstreamRest.class, linkClass = BitstreamRest.class,
method = "getBitstreams", method = "getBitstreams"
embedOptional = true
), ),
@LinkRest( @LinkRest(
name = BundleRest.PRIMARY_BITSTREAM, name = BundleRest.PRIMARY_BITSTREAM,
linkClass = BitstreamRest.class, linkClass = BitstreamRest.class,
method = "getPrimaryBitstream", method = "getPrimaryBitstream"
embedOptional = true
) )
}) })
public class BundleRest extends DSpaceObjectRest { public class BundleRest extends DSpaceObjectRest {

View File

@@ -18,26 +18,22 @@ import com.fasterxml.jackson.annotation.JsonProperty;
@LinkRest( @LinkRest(
name = CollectionRest.DEFAULT_ACCESS_CONDITIONS, name = CollectionRest.DEFAULT_ACCESS_CONDITIONS,
linkClass = ResourcePolicyRest.class, linkClass = ResourcePolicyRest.class,
method = "getDefaultAccessConditions", method = "getDefaultAccessConditions"
embedOptional = true
), ),
@LinkRest( @LinkRest(
name = CollectionRest.LICENSE, name = CollectionRest.LICENSE,
linkClass = LicenseRest.class, linkClass = LicenseRest.class,
method = "getLicense", method = "getLicense"
embedOptional = true
), ),
@LinkRest( @LinkRest(
name = CollectionRest.LOGO, name = CollectionRest.LOGO,
linkClass = BitstreamRest.class, linkClass = BitstreamRest.class,
method = "getLogo", method = "getLogo"
embedOptional = true
), ),
@LinkRest( @LinkRest(
name = CollectionRest.MAPPED_ITEMS, name = CollectionRest.MAPPED_ITEMS,
linkClass = ItemRest.class, linkClass = ItemRest.class,
method = "getMappedItems", method = "getMappedItems"
embedOptional = true
) )
}) })
public class CollectionRest extends DSpaceObjectRest { public class CollectionRest extends DSpaceObjectRest {

View File

@@ -18,20 +18,17 @@ import com.fasterxml.jackson.annotation.JsonProperty;
@LinkRest( @LinkRest(
name = CommunityRest.COLLECTIONS, name = CommunityRest.COLLECTIONS,
linkClass = CollectionRest.class, linkClass = CollectionRest.class,
method = "getCollections", method = "getCollections"
embedOptional = true
), ),
@LinkRest( @LinkRest(
name = CommunityRest.LOGO, name = CommunityRest.LOGO,
linkClass = BitstreamRest.class, linkClass = BitstreamRest.class,
method = "getLogo", method = "getLogo"
embedOptional = true
), ),
@LinkRest( @LinkRest(
name = CommunityRest.SUBCOMMUNITIES, name = CommunityRest.SUBCOMMUNITIES,
linkClass = CommunityRest.class, linkClass = CommunityRest.class,
method = "getSubcommunities", method = "getSubcommunities"
embedOptional = true
) )
}) })
public class CommunityRest extends DSpaceObjectRest { public class CommunityRest extends DSpaceObjectRest {

View File

@@ -23,8 +23,7 @@ import org.dspace.app.rest.RestResourceController;
@LinkRest( @LinkRest(
name = EPersonRest.GROUPS, name = EPersonRest.GROUPS,
linkClass = GroupRest.class, linkClass = GroupRest.class,
method = "getGroups", method = "getGroups"
embedOptional = true
) )
}) })
public class EPersonRest extends DSpaceObjectRest { public class EPersonRest extends DSpaceObjectRest {

View File

@@ -21,8 +21,7 @@ import org.dspace.app.rest.RestResourceController;
@LinkRest( @LinkRest(
name = GroupRest.GROUPS, name = GroupRest.GROUPS,
linkClass = GroupRest.class, linkClass = GroupRest.class,
method = "getGroups", method = "getGroups"
embedOptional = true
) )
}) })
public class GroupRest extends DSpaceObjectRest { public class GroupRest extends DSpaceObjectRest {

View File

@@ -156,7 +156,7 @@ public class HarvestedCollectionRest extends BaseObjectRest<Integer> {
this.lastHarvested = lastHarvested; this.lastHarvested = lastHarvested;
} }
@LinkRest(linkClass = HarvesterMetadataRest.class, name = "harvestermetadata", linkOptional = true) @LinkRest(linkClass = HarvesterMetadataRest.class, name = "harvestermetadata")
@JsonIgnore @JsonIgnore
public HarvesterMetadataRest getMetadataConfigs() { public HarvesterMetadataRest getMetadataConfigs() {
return metadata_configs; return metadata_configs;

View File

@@ -20,32 +20,27 @@ import com.fasterxml.jackson.annotation.JsonProperty;
@LinkRest( @LinkRest(
name = ItemRest.BUNDLES, name = ItemRest.BUNDLES,
linkClass = BundleRest.class, linkClass = BundleRest.class,
method = "getBundles", method = "getBundles"
embedOptional = true
), ),
@LinkRest( @LinkRest(
name = ItemRest.MAPPED_COLLECTIONS, name = ItemRest.MAPPED_COLLECTIONS,
linkClass = CollectionRest.class, linkClass = CollectionRest.class,
method = "getMappedCollections", method = "getMappedCollections"
embedOptional = true
), ),
@LinkRest( @LinkRest(
name = ItemRest.OWNING_COLLECTION, name = ItemRest.OWNING_COLLECTION,
linkClass = CollectionRest.class, linkClass = CollectionRest.class,
method = "getOwningCollection", method = "getOwningCollection"
embedOptional = true
), ),
@LinkRest( @LinkRest(
name = ItemRest.RELATIONSHIPS, name = ItemRest.RELATIONSHIPS,
linkClass = RelationshipRest.class, linkClass = RelationshipRest.class,
method = "getRelationships", method = "getRelationships"
embedOptional = true
), ),
@LinkRest( @LinkRest(
name = ItemRest.TEMPLATE_ITEM_OF, name = ItemRest.TEMPLATE_ITEM_OF,
linkClass = CollectionRest.class, linkClass = CollectionRest.class,
method = "getTemplateItemOf", method = "getTemplateItemOf"
embedOptional = true
) )
}) })
public class ItemRest extends DSpaceObjectRest { public class ItemRest extends DSpaceObjectRest {

View File

@@ -14,7 +14,6 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import org.dspace.app.rest.model.hateoas.HALResource; import org.dspace.app.rest.model.hateoas.HALResource;
import org.dspace.app.rest.projection.Projection;
import org.dspace.app.rest.repository.LinkRestRepository; import org.dspace.app.rest.repository.LinkRestRepository;
import org.dspace.app.rest.utils.Utils; import org.dspace.app.rest.utils.Utils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -63,37 +62,4 @@ public @interface LinkRest {
* @return the class. * @return the class.
*/ */
Class linkClass(); Class linkClass();
/**
* Tells whether embedding the resource indicated by this link is optional.
* <p>
* If false (the default), it means the resource will always be embedded unless the {@link LinkRestRepository}
* forbids it via {@link LinkRestRepository#isEmbeddableRelation(Object, String)}.
* </p>
* <p>
* If true, it means the resource will be embedded normally, unless forbidden by the {@link LinkRestRepository}
* or the projection, in use, via {@link Projection#allowOptionalEmbed(HALResource, LinkRest)}.
* </p>
*
* @return whether embedding is optional.
*/
boolean embedOptional() default false;
/**
* Tells whether linking the resource indicated by this link is optional.
* <p>
* If false (the default), it means the resource will always be linked.
* </p>
* <p>
* If true, it means the resource will only be linked if:
* <ul>
* <li> The resource is embedded, or</li>
* <li> The value returned by the link method is not null and linking is not forbidden by the
* projection in use, via {@link Projection#allowOptionalLink(HALResource, LinkRest)}</li>
* </ul>
* </p>
*
* @return whether linking is optional.
*/
boolean linkOptional() default false;
} }

View File

@@ -445,10 +445,10 @@ public class Utils {
Projection projection = halResource.getContent().getProjection(); Projection projection = halResource.getContent().getProjection();
getLinkRests(halResource.getContent().getClass()).stream().forEach((linkRest) -> { getLinkRests(halResource.getContent().getClass()).stream().forEach((linkRest) -> {
Link link = linkToSubResource(halResource.getContent(), linkRest.name()); Link link = linkToSubResource(halResource.getContent(), linkRest.name());
if (!linkRest.embedOptional() || projection.allowEmbedding(halResource, linkRest)) { if (projection.allowEmbedding(halResource, linkRest)) {
embedRelFromRepository(halResource, linkRest.name(), link, linkRest); embedRelFromRepository(halResource, linkRest.name(), link, linkRest);
halResource.add(link); // unconditionally link if embedding was allowed halResource.add(link); // unconditionally link if embedding was allowed
} else if (!linkRest.linkOptional() || projection.allowLinking(halResource, linkRest)) { } else if (projection.allowLinking(halResource, linkRest)) {
halResource.add(link); halResource.add(link);
} }
}); });
@@ -492,9 +492,7 @@ public class Utils {
Object contentId = getContentIdForLinkMethod(resource.getContent(), method); Object contentId = getContentIdForLinkMethod(resource.getContent(), method);
try { try {
Object linkedObject = method.invoke(linkRepository, null, contentId, null, projection); Object linkedObject = method.invoke(linkRepository, null, contentId, null, projection);
if (linkedObject != null || !linkRest.embedOptional()) {
resource.embedResource(rel, wrapForEmbedding(linkedObject, link)); resource.embedResource(rel, wrapForEmbedding(linkedObject, link));
}
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
if (e.getTargetException() instanceof RuntimeException) { if (e.getTargetException() instanceof RuntimeException) {
throw (RuntimeException) e.getTargetException(); throw (RuntimeException) e.getTargetException();
@@ -559,8 +557,7 @@ public class Utils {
LinkRest linkRest = findLinkAnnotation(readMethod); LinkRest linkRest = findLinkAnnotation(readMethod);
try { try {
if (linkRest != null) { if (linkRest != null) {
if (linkRest.embedOptional() if (!resource.getContent().getProjection().allowEmbedding(resource, linkRest)) {
&& !resource.getContent().getProjection().allowEmbedding(resource, linkRest)) {
return; // projection disallows this optional method-level embed return; // projection disallows this optional method-level embed
} }
if (StringUtils.isNotBlank(linkRest.name())) { if (StringUtils.isNotBlank(linkRest.name())) {
@@ -569,9 +566,7 @@ public class Utils {
Link link = linkToSubResource(resource.getContent(), rel); Link link = linkToSubResource(resource.getContent(), rel);
if (StringUtils.isBlank(linkRest.method())) { if (StringUtils.isBlank(linkRest.method())) {
Object linkedObject = readMethod.invoke(resource.getContent()); Object linkedObject = readMethod.invoke(resource.getContent());
if (linkedObject != null || !linkRest.embedOptional()) {
resource.embedResource(rel, wrapForEmbedding(linkedObject, link)); resource.embedResource(rel, wrapForEmbedding(linkedObject, link));
}
} else { } else {
embedRelFromRepository(resource, rel, link, linkRest); embedRelFromRepository(resource, rel, link, linkRest);
} }

View File

@@ -17,15 +17,12 @@ import org.dspace.app.rest.projection.Projection;
@LinkRest( @LinkRest(
name = MockObjectRest.O_CHILDREN, name = MockObjectRest.O_CHILDREN,
linkClass = MockObjectRest.class, linkClass = MockObjectRest.class,
method = "getMockObjectChildren", method = "getMockObjectChildren"
embedOptional = true,
linkOptional = true
), ),
@LinkRest( @LinkRest(
name = MockObjectRest.A_CHILDREN, name = MockObjectRest.A_CHILDREN,
linkClass = MockObjectRest.class, linkClass = MockObjectRest.class,
method = "getMockObjectChildren", method = "getMockObjectChildren"
linkOptional = true
), ),
@LinkRest( @LinkRest(
name = MockObjectRest.N_CHILDREN, name = MockObjectRest.N_CHILDREN,
@@ -90,7 +87,7 @@ public class MockObjectRest extends BaseObjectRest<Long> {
this.value = value; this.value = value;
} }
@LinkRest(linkClass = MockObjectRest.class, linkOptional = true) @LinkRest(linkClass = MockObjectRest.class)
public MockObjectRest getRestProp1() { public MockObjectRest getRestProp1() {
return restProp1; return restProp1;
} }
@@ -99,7 +96,7 @@ public class MockObjectRest extends BaseObjectRest<Long> {
this.restProp1 = restProp1; this.restProp1 = restProp1;
} }
@LinkRest(linkClass = MockObjectRest.class, embedOptional = true, linkOptional = true) @LinkRest(linkClass = MockObjectRest.class)
public MockObjectRest getRestProp2() { public MockObjectRest getRestProp2() {
return restProp2; return restProp2;
} }
@@ -108,7 +105,7 @@ public class MockObjectRest extends BaseObjectRest<Long> {
this.restProp2 = restProp2; this.restProp2 = restProp2;
} }
@LinkRest(linkClass = MockObjectRest.class, embedOptional = true, linkOptional = true) @LinkRest(linkClass = MockObjectRest.class)
public MockObjectRest getRestProp3() { public MockObjectRest getRestProp3() {
return restProp3; return restProp3;
} }
@@ -117,7 +114,7 @@ public class MockObjectRest extends BaseObjectRest<Long> {
this.restProp3 = restProp3; this.restProp3 = restProp3;
} }
@LinkRest(linkClass = MockObjectRest.class, embedOptional = true) @LinkRest(linkClass = MockObjectRest.class)
public MockObjectRest getRestProp4() { public MockObjectRest getRestProp4() {
return restProp4; return restProp4;
} }