crnk-project / crnk-framework

JSON API library for Java
Apache License 2.0
287 stars 156 forks source link

Convert an entity object to document, in the document filter #688

Open goldyliang opened 4 years ago

goldyliang commented 4 years ago

I have a need to convert an entity object to a Document object so it can be returned to user directly, but can not find out the obvious way.

The code I am targeting is like below:

@Component
public class MyDocumentFilter implements DocumentFilter {
 ...
 ...
  @Override
  public Response filter(DocumentFilterContext filterRequestContext, DocumentFilterChain chain) {
       ...
      if (filterRequestContext.getMethod().equals("POST") && 
         // other conditions ) {
       ...
            // MyService.handleRequest is legacy code, which I don't want to re-factor it to fit the way 
           // how DocumentFilter works.
           // The method is called as it was, returning a persisted entity object.
           MyEntity entity = MyService.handleRequest(...);

          // How can I convert entity to a document, so it can be returned as a result?
          //  Document document = Some_Convert_Method (entity);
          //  return new Response(document, HttpStatus.OK.value());
      }
  }
}

The only way I can find (which is ugly), is like below:

    ResourceGetController controller  = crnkBoot
                    .getControllerRegistry()
                    .getControllers()
                    .stream()
                    .filter(c -> c instanceof ResourceGetController)
                    .findFirst()
                    .get();

   JsonPath path =
            new ResourcePath(
                filterRequestContext.getJsonPath().getRootEntry(),
                Arrays.asList(element.getUuid()));

   QuerySpec querySpec = new QuerySpec(MyEntity.class, "type-name");
   QueryAdapter adapter =
            new QuerySpecAdapter(
                querySpec,
                filterRequestContext.getQueryAdapter().getResourceRegistry(),
                filterRequestContext.getQueryAdapter().getQueryContext());

  return controller.handleAsync(artifactPath, adapter, null);
remmeier commented 4 years ago

You can get an instance of DocumentMapper (which behind the scenes makes use of ResourceMapper from CrnkBoot/ModuleRegistry. This gives a Document object that can easily be translated to JSON with Jackson.

goldyliang commented 4 years ago

Thanks @remmeier . So following your suggestion, my code would be something like below.

I verified that it works fine.

        DocumentMapper mapper = crnkBoot.getDocumentMapper();

        QuerySpec querySpec = new QuerySpec(MyEntity.class, "type-name");
        QueryAdapter adapter =
                new QuerySpecAdapter(
                        querySpec,
                        filterRequestContext.getQueryAdapter().getResourceRegistry(),
                        filterRequestContext.getQueryAdapter().getQueryContext());

        Document result = mapper.toDocument( new JsonApiResponse() {{
          setEntity(entity);
                           }}, adapter, crnkBoot.getModuleRegistry().getDocumentMappingConfig()).get();

        return new Response(result, HttpStatus.CREATED.value());
goldyliang commented 4 years ago

But the next question is, what is the correct way to get CrnkBoot instance? I tried auto-wired it in the document filter, but the application does not start, seems like due to some initialization order issue.

Now I had to create a component to extend CrnkBootConfigurer so as to get the instance and remember it.