Skip to content

Create a dedicated builder for HAL representations #864

Closed
@gregturn

Description

@gregturn

@drdamour I'm experimenting on a fluent API to build RepresentationModel objects. What do you think of something like this for building an embedded structure like you depicted up above?

@RestController
static class ProductController {

	LinkRelation favoriteProducts = LinkRelation.of("favorite products");
	LinkRelation purchasedProducts = LinkRelation.of("purchased products");

	@GetMapping("/products")
	public RepresentationModel<?> all() {

		EmbeddedModelBuilder builder = ModelBuilder //
				.embed() //
				.rootLink(linkTo(methodOn(ProductController.class).all()).withSelfRel());

		PRODUCTS.keySet().stream() //
				.map(id -> new EntityModel<>(PRODUCTS.get(id), new Link("http://localhost/products/{id}").expand(id))) //
				.forEach(productEntityModel -> {

					if (productEntityModel.getContent().isFavorite()) {

						builder //
								.embed(favoriteProducts) //
								.entityModel(productEntityModel) //
								.rootLink(productEntityModel.getRequiredLink(SELF).withRel(favoriteProducts));
					}

					if (productEntityModel.getContent().isPurchased()) {

						builder //
								.embed(purchasedProducts) //
								.entityModel(productEntityModel) //
								.rootLink(productEntityModel.getRequiredLink(SELF).withRel(purchasedProducts));
					}
				});

		return builder.build();
	}
}

It yields:

{
  "_embedded" : {
    "favorite products" : [ {
      "someProductProperty" : "someValue",
      "_links" : {
        "self" : {
          "href" : "http://localhost/products/777"
        }
      }
    }, {
      "someProductProperty" : "someValue",
      "_links" : {
        "self" : {
          "href" : "http://localhost/products/998"
        }
      }
    } ],
    "purchased products" : [ {
      "someProductProperty" : "someValue",
      "_links" : {
        "self" : {
          "href" : "http://localhost/products/111"
        }
      }
    }, {
      "someProductProperty" : "someValue",
      "_links" : {
        "self" : {
          "href" : "http://localhost/products/222"
        }
      }
    }, {
      "someProductProperty" : "someValue",
      "_links" : {
        "self" : {
          "href" : "http://localhost/products/333"
        }
      }
    }, {
      "someProductProperty" : "someValue",
      "_links" : {
        "self" : {
          "href" : "http://localhost/products/444"
        }
      }
    }, {
      "someProductProperty" : "someValue",
      "_links" : {
        "self" : {
          "href" : "http://localhost/products/555"
        }
      }
    }, {
      "someProductProperty" : "someValue",
      "_links" : {
        "self" : {
          "href" : "http://localhost/products/666"
        }
      }
    }, {
      "someProductProperty" : "someValue",
      "_links" : {
        "self" : {
          "href" : "http://localhost/products/998"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost/products"
    },
    "purchased products" : [ {
      "href" : "http://localhost/products/111"
    }, {
      "href" : "http://localhost/products/222"
    }, {
      "href" : "http://localhost/products/333"
    }, {
      "href" : "http://localhost/products/444"
    }, {
      "href" : "http://localhost/products/555"
    }, {
      "href" : "http://localhost/products/666"
    }, {
      "href" : "http://localhost/products/998"
    } ],
    "favorite products" : [ {
      "href" : "http://localhost/products/777"
    }, {
      "href" : "http://localhost/products/998"
    } ]
  }
}

A plain old collection where the embedded link relation is a based on the domain type:

@GetMapping("/authors")
RepresentationModel<?> collection() {

	return ModelBuilder //
			.collection() //

			.entity(new Author("Greg L. Turnquist", null, null)) //
			.link(linkTo(methodOn(EmbeddedController.class).authorDetails(1)).withSelfRel())
			.link(linkTo(methodOn(EmbeddedController.class).collection()).withRel("authors")) //

			.entity(new Author("Craig Walls", null, null)) //
			.link(linkTo(methodOn(EmbeddedController.class).authorDetails(2)).withSelfRel())
			.link(linkTo(methodOn(EmbeddedController.class).collection()).withRel("authors")) //

			.entity(new Author("Oliver Drotbhom", null, null)) //
			.link(linkTo(methodOn(EmbeddedController.class).authorDetails(2)).withSelfRel())
			.link(linkTo(methodOn(EmbeddedController.class).collection()).withRel("authors")) //

			.rootLink(linkTo(methodOn(EmbeddedController.class).collection()).withSelfRel()) //

			.build();
}

produces

{
  "_embedded" : {
    "authors" : [ {
      "name" : "Greg L. Turnquist",
      "_links" : {
        "self" : {
          "href" : "http://localhost/author/1"
        },
        "authors" : {
          "href" : "http://localhost/authors"
        }
      }
    }, {
      "name" : "Craig Walls",
      "_links" : {
        "self" : {
          "href" : "http://localhost/author/2"
        },
        "authors" : {
          "href" : "http://localhost/authors"
        }
      }
    }, {
      "name" : "Oliver Drotbhom",
      "_links" : {
        "self" : {
          "href" : "http://localhost/author/2"
        },
        "authors" : {
          "href" : "http://localhost/authors"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost/authors"
    }
  }
}

And a single item representation:

@GetMapping("/other-author")
RepresentationModel<?> singleItem() {

	return ModelBuilder //
			.entity(new Author("Alan Watts", "January 6, 1915", "November 16, 1973")) //
			.link(new Link("/people/alan-watts")) //
			.build();
}

produces

{
  "name" : "Alan Watts",
  "born" : "January 6, 1915",
  "died" : "November 16, 1973",
  "_links" : {
    "self" : {
      "href" : "/people/alan-watts"
    }
  }
}

Related issue: #175

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions