jackson-dataformat-hal icon indicating copy to clipboard operation
jackson-dataformat-hal copied to clipboard

ResourceSupport<T>, ResourceCollectionSupport<T>

Open dherges opened this issue 5 years ago • 2 comments

Here is an example how to add HAL resource support to an existing application where you already have a large set of domain entities.

The trick is to use a @JsonUnwrapped around the existing entity. You have a large set of existing classes that you don't want to / or cannot modify. Then, with ResourceSupport and ResourceCollectionSupport it becomes easy to add the findAll(), findOne(ID id) features.

The Supporting Cast

@Resource
public abstract class ResourceSupport<T> {

    @Link
    public final HALLink self;

    @JsonUnwrapped
    public final T domain;

    public ResourceSupport(Link self, T domain) {
        this.self = self;
        this.domain = domain;
    }
}

@Resource
public abstract class ResourceCollectionSupport<T> {

    @Link
    public final HALLink self;

    @EmbeddedResource
    public final Collection<ResourceSupport<T>> content;

    public ResourceCollectionSupport(Link self, Collection<ResourceSupport<T>> domain) {
        this.self = self;
        this.content = domain;
    }
}

The Boilerplate


    public static class Foo {
        public UUID id = UUID.randomUUID();
        public String foo = "bar";
    }

    public static class Bar {
        public BigInteger bar = BigInteger.ZERO;
    }

    public static class FooResourceSupport extends ResourceSupport<Foo> {

        public FooResourceSupport(Foo foo) {
            super(new Link.Builder("/foo/" + foo.id.toString()).build(), foo);
        }
    }

    public static class BarResourceSupport extends ResourceSupport<Bar> {

        public BarResourceSupport(Bar bar) {
            super(new Link.Builder("/bar/" + bar.bar).build(), bar);
        }

        @EmbeddedResource(value = "thisIsTheDimensionsObject")
        public FooResourceSupport dimensions;
    }

    public static class FooCollectionResource extends ResourceCollectionSupport<Foo> {

        public FooCollectionResource(Collection<Foo> domain) {
            super(new Link.Builder("/foo").build(), domain.stream().map(FooResourceSupport::new).collect(Collectors.toList()));
        }
    }

dherges avatar Nov 23 '18 11:11 dherges

Ah yes, deserialization breaks with non-default constructors ...

dherges avatar Nov 23 '18 11:11 dherges

Seems a simple way to wrap a model that is out of your own control. Considering if we should add this to the README.

langecode avatar Nov 24 '18 10:11 langecode