/* * Copyright 2012-2015 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.data.rest.webmvc; import lombok.Getter; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.hateoas.Link; import org.springframework.hateoas.Resource; import org.springframework.hateoas.Resources; import org.springframework.hateoas.core.EmbeddedWrapper; import org.springframework.util.Assert; import com.fasterxml.jackson.annotation.JsonIgnore; /** * A Spring HATEOAS {@link Resource} subclass that holds a reference to the entity's {@link PersistentEntity} metadata. * * @author Jon Brisbin * @author Oliver Gierke */ public class PersistentEntityResource extends Resource<Object> { private static final Iterable<EmbeddedWrapper> NO_EMBEDDEDS = new NoLinksResources<EmbeddedWrapper>( Collections.<EmbeddedWrapper> emptyList()); private final PersistentEntity<?, ?> entity; private final Iterable<EmbeddedWrapper> embeddeds; /** * Returns whether the content of the resource is a new entity about to be created. Used to distinguish between * creation and updates for incoming requests. * * @return */ private final @Getter boolean isNew; private final @Getter boolean nested; /** * Creates a new {@link PersistentEntityResource} for the given {@link PersistentEntity}, content, embedded * {@link Resources}, links and flag whether to render all associations. * * @param entity must not be {@literal null}. * @param content must not be {@literal null}. * @param links must not be {@literal null}. * @param embeddeds can be {@literal null}. */ private PersistentEntityResource(PersistentEntity<?, ?> entity, Object content, Iterable<Link> links, Iterable<EmbeddedWrapper> embeddeds, boolean isNew, boolean nested) { super(content, links); Assert.notNull(entity, "PersistentEntity must not be null!"); this.entity = entity; this.embeddeds = embeddeds == null ? NO_EMBEDDEDS : embeddeds; this.isNew = isNew; this.nested = nested; } /** * Returns the {@link PersistentEntity} for the underlying instance. * * @return */ public PersistentEntity<?, ? extends PersistentProperty<?>> getPersistentEntity() { return entity; } /** * Returns the {@link PersistentPropertyAccessor} for the underlying content bean. * * @return */ public PersistentPropertyAccessor getPropertyAccessor() { return entity.getPropertyAccessor(getContent()); } /** * Returns the resources that are supposed to be rendered in the {@code _embedded} clause. * * @return the embeddeds */ public Iterable<EmbeddedWrapper> getEmbeddeds() { return embeddeds; } /** * Creates a new {@link Builder} to create {@link PersistentEntityResource}s eventually. * * @param content must not be {@literal null}. * @param entity must not be {@literal null}. * @return */ public static Builder build(Object content, PersistentEntity<?, ?> entity) { return new Builder(content, entity); } /** * Builder to create {@link PersistentEntityResource} instances. * * @author Oliver Gierke */ public static class Builder { private final Object content; private final PersistentEntity<?, ?> entity; private final List<Link> links = new ArrayList<Link>(); private Iterable<EmbeddedWrapper> embeddeds; /** * Creates a new {@link Builder} instance for the given content and {@link PersistentEntity}. * * @param content must not be {@literal null}. * @param entity must not be {@literal null}. */ private Builder(Object content, PersistentEntity<?, ?> entity) { Assert.notNull(content, "Content must not be null!"); Assert.notNull(entity, "PersistentEntity must not be null!"); this.content = content; this.entity = entity; } /** * Configures the builder to embed the given {@link EmbeddedWrapper} instances. Creates a {@link Resources} instance * to make sure the {@link EmbeddedWrapper} handling gets applied to the serialization output ignoring the links. * * @param resources can be {@literal null}. * @return the builder */ public Builder withEmbedded(Iterable<EmbeddedWrapper> resources) { this.embeddeds = resources == null ? null : new NoLinksResources<EmbeddedWrapper>(resources); return this; } /** * Adds the given {@link Link} to the {@link PersistentEntityResource}. * * @param link must not be {@literal null}. * @return the builder */ public Builder withLink(Link link) { Assert.notNull(link, "Link must not be null!"); this.links.add(link); return this; } public Builder withLinks(List<Link> links) { Assert.notNull(links, "Links must not be null!"); this.links.addAll(links); return this; } /** * Finally creates the {@link PersistentEntityResource} instance. * * @return */ public PersistentEntityResource build() { return new PersistentEntityResource(entity, content, links, embeddeds, false, false); } /** * Finally creates the {@link PersistentEntityResource} instance to symbolize the contained entity is about to be * created. * * @return */ public PersistentEntityResource forCreation() { return new PersistentEntityResource(entity, content, links, embeddeds, true, false); } public PersistentEntityResource buildNested() { return new PersistentEntityResource(entity, content, links, embeddeds, false, true); } } private static class NoLinksResources<T> extends Resources<T> { public NoLinksResources(Iterable<T> content) { super(content); } /* * (non-Javadoc) * @see org.springframework.hateoas.ResourceSupport#getLinks() */ @Override @JsonIgnore public List<Link> getLinks() { return super.getLinks(); } } }