toedter / spring-hateoas-jsonapi

A JSON:API media type implementation for Spring HATEOAS
Apache License 2.0
107 stars 15 forks source link

JsonApiModelBuilder is not compatible with ReactiveRepresentationModelAssembler #61

Closed jimirocks closed 2 years ago

jimirocks commented 2 years ago

As I commented on #59 (after close), I believe it should be possible to use JsonApiModelBuilder while implementing ReactiveRepresentationModelAssembler but it's not. See the code, which can't compile on the class declaration:

import com.toedter.spring.hateoas.jsonapi.JsonApiModelBuilder;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.reactive.ReactiveRepresentationModelAssembler;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public class JavaAssembler extends ReactiveRepresentationModelAssembler<MyStupidDto, RepresentationModel<?>> {
    @Override
    public Mono<RepresentationModel<?>> toModel(final MyStupidDto entity, final ServerWebExchange exchange) {
        return Mono.just(JsonApiModelBuilder.jsonApiModel().model(entity).build());
    }

    @Override
    public Mono<CollectionModel<RepresentationModel<?>>> toCollectionModel(final Flux<? extends MyStupidDto> entities, final ServerWebExchange exchange) {
        throw new UnsupportedOperationException("not implemented");
    }
}

I see two possible solutions:

  1. Making JsonApiModel public - as suggested in #59
  2. changing the generics of ReactiveRepresentationModelAssembler to <T, D extends RepresentationModel<?>> from <T, D extends RepresentationModel<D>>
toedter commented 2 years ago

The code does not compile because D extends RepresentationModel<D>> is required in the signature, not RepresentationModel<?>. But the only thing a ReactiveRepresentationModelAssembler implements, is one line of code in the method toCollectionModel. This original method does not make sense when using JsonApiModels because a JsonApiModelcan reprersent a collection model itself.

If you want to use an assembler to create representation models, you can easily build your own, like.

public class MyAssembler {
    public Mono<RepresentationModel<?>> toModel(final MyStupidDto entity, final ServerWebExchange exchange) {
        return Mono.just(JsonApiModelBuilder.jsonApiModel().model(entity).build());
    }

    public Mono<RepresentationModel<?>> toCollectionModel(Flux<? extends MyStupidDto> entities, ServerWebExchange exchange) {
       // use the builder here to create a JsonApiModel based on entities
    }
}

So why would you like to re-use ReactiveRepresentationModelAssembler at all?

jimirocks commented 2 years ago

You are right, that we can bypass ReactiveRepresentationModelAssembler - nothing basically forces us to use that particular interface. So this issue is not anyhow blocking us.

But the fact JsonApiModeBuilder is not compatible with ReactiveRepresentationModelAssembler is still here...

toedter commented 2 years ago

@jimirocks you wrote: But the fact JsonApiModeBuilderis not compatible with ReactiveRepresentationModelAssembleris still here...

yes, you are right, but the main reason for that is that those assembler interfaces were designed to work mostly with the build-in EntityModeland CollectionModel implementations in mind.

What I was actually thinking about was to create JsonApiModel wrappers to wrap JsonApiModels in EntityModels and CollectionModels, but unfortunatelly it turned to be way more complicated than expected...

Since it is no blocker for you I would close this issue and think further about the wraping :)

jimirocks commented 2 years ago

yes, you are right, but the main reason for that is that those assembler interfaces were designed to work mostly with the build-in EntityModel and CollectionModel implementations in mind.

Ahh ha so that was the missing piece of puzzle to understand. Thank you for explanation.

We will go with custom interface....

toedter commented 2 years ago

Just fyi, I filed an issue at Spring HATEOAS: https://github.com/spring-projects/spring-hateoas/issues/1796