Anyway to provide custom PagedResourcesAssembler implementation? - spring-data-rest

I am under a requirement of exclude the "first" and "last" in the _links section of the response. Based on the spring data rest code, it seems I should provide custom PagedResourcesAssembler implementation to achieve this.
I try to subclass RepositoryRestMvcConfiguration to "overrides" the pageableResolver bean but with no luck. No error occurs but the "first" and "last" property is still returned. You can get the code at my github repo
Anybody have a solution here?

I didn't went through your solution on github step by step, but it seems you only have overridden only one toResource method in the PagedResourceAssembler.
However that's an overloaded method, and I assume most of the time the other variants are called.
So, simply override all of the others too:
public PagedResources<Resource<T>> toResource(Page<T> entity);
public PagedResources<Resource<T>> toResource(Page<T> page, Link selfLink);
public <R extends ResourceSupport> PagedResources<R> toResource(Page<T> page, ResourceAssembler<T, R> assembler);
public <R extends ResourceSupport> PagedResources<R> toResource(Page<T> page, ResourceAssembler<T, R> assembler, Link link);
Oh, and don't forget to override all of the toEmptyResource methods too!

Related

Quarkus: custom SecurityIdentity

In a quarkus app, I'd like to develop my own SecurityIdentity, because existing ones do not fit my need (I need to check identity by getting roles from multiple micro-services). Maybe a custom SecurityIdentity is not the best option, but looking at documentation it seems to be what I need (another option is to define a ContainerRequestFilter implementation but this is at lower level and less integrated).
Is there any way to do it? I tested the following:
#Provider
#PreMatching
class CustomSecurityIdentity: SecurityIdentity {
override fun getPrincipal(): Principal {
....
Then from an endpoint I simply defined:
#GET
#Produces(MediaType.APPLICATION_JSON)
#RolesAllowed("administrator")
#Path("/")
fun checkAuth(): Response {
...
I put some breakpoints everywhere but it never comes through my Identity Provider where the #RolesAllowed should (the way I see it) force it.
Is it possible to make it work?

How to use a #FeignClient to map a HAL JSON _embedded collection

We're trying to use a spring-cloud #FeignClient to call the HAL-JSON REST API of a microservice from another microservice. The service is implemented with Spring Data Rest, Spring Boot 1.4, with Hateoas enabled by default.
Using a dedicated DTO on the client side, all the simple properties are properly mapped, but the HAL-specific _embedded collection is ignored.
As taken primarly from this post, we implemented a custom Feign Decoder with a corresponding ObjectMapper, using the often mentioned Jackson2HalModule, but this still does not solve our issue.
You can reproduce the issue with this sample project, where the problem is described in more detail.
We appreciate any help or hints on this problem! Thanks in advance
I think the key to understanding how to deserialize this is that your Customer is the Resources class that is embedding the relations. So you need to deserialize it as Resources in order for the HalResourcesDeserializer to pick it up.
I got it to work this way.
#Getter
#Setter
public class Customer extends Resources<Resource<Relation>> {
public static enum Type {
PERSON, INSTITUTION
}
private String displayName;
private Integer rating;
private Type type;
public Collection<Resource<Relation>> getRelations() {
return this.getContent();
}
}
This still looks a little odd and I am not sure if this is the best solution.
I know I am responding to an old question, but in my experience, I had to add #EnableHyperMediaSupport to my main/any configuration class to resolve this issue. You can try that and verify if it works for you.

Can I create a request-scoped object and access it from anywhere, and avoid passing it around as a parameter in JAX-RS?

Say I have a web service / a REST resource that is called with some HTTP header parameters. The resource method builds a complex data object (currently a POJO) and eventually returns it to the client (via Gson as JSON, but that doesn't matter).
So I have this call hierarchy:
#Path(foo) ProjectResource #GET getProject()
-> new Project()
-> new List<Participant> which contains lots of new Participant()s
-> new Affiliation()
If I want the Affiliation object to be e.g. populated in English or German depending on a header parameter, I have to pass that as a parameter down the chain. I want to avoid having to do that. Maybe this is just fundamentally impossible, but it feels so wrong. All these objects only live inside the request, so wouldn't it be convenient to be able to access information tied to the request from anywhere?
I was hoping I could e.g. define a CDI #RequestScoped object that initialized itself (or gets populated by some WebFilter) and that I can then inject where I might need it.
But obviously that doesn't work from inside the POJOs, and I also had trouble getting hold of the headers from inside the request-scoped object.
I've read many SO questions/answers about EJBs and JAX-RS Context and CDI but I can't wrap my head around it.
Am I expecting too much? Is passing down the parameter really the preferred option?
If I understand what you need, you can try the following (just wrote this solution from the top of my head, but it should work):
Defining a class to store the data you need
Define a class annotated with #RequestScoped which will store the data you need:
#RequestScoped
public class RequestMetadata {
private Locale language;
// Default constructor, getters and setters ommited
}
Ensure you are using the #RequestScoped annotation from the javax.enterprise.context package.
Creating a request filter
Create a ContainerRequestFilter to populate the RequestMetadata:
#Provider
#PreMatching
public class RequestMetadataFilter implements ContainerRequestFilter {
#Inject
private RequestMetadata requestMetadata;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
requestMetadata.setLanguage(requestContext.getLanguage());
}
}
Performing the injection
And then you can finally perform the injection of the RequestMetadata using #Inject:
#Stateless
public class Foo {
#Inject
private RequestMetadata requestMetadata;
...
}
Please, be aware that anywhere is too broad: The injection will work into beans managed by the container, such as servlets, JAX-RS classes, EJB and CDI beans, for example.
You won't be able to perform injections into beans created by yourself neither into JPA entities.

What dependency injection pattern to use for a MessageProvider?

I have a ContactController where I set up a message in the TempData (this is to display a message in the screen after successful submission) and in the layout, there's a partial _Message.cshtml that is supposed to render the message, if any. Method signatures below:
List<Message> GetMessages(IDictionary<string, object> dictionary);
void SetMessage(IDictionary<string, object> dictionary, string body, MessageType type);
Initially I thought about having a MessageProvider dependency injected in the constructor. But then it occurred to me: What if I need do this in other controllers? Besides, for me to use it in the partial view, I need to resolve the implementation from the container which I think is an acceptable solution to use in a class that extends WebViewPage (considering I am not going to unit test it).
public MyCustomViewPage()
{
this.MessageProvider = DependencyResolver.Current.GetService<MessageProvider>();
}
public MessageProvider MessageProvider { get; set; }
But can we avoid the Service Locator anti-pattern using another dependency injection pattern?
I was thinking this MessageProvider has a good default implementation and since we might need to use this in more controllers in the future, this might be a good candidate for Ambient Context design pattern as per the book Dependency Injection in .NET by Mark Seemann.
This way, I would eliminate the potential problem of having to change other controller constructors in the future in case I happen to have to set messages in them, I would eliminate the need to use the Service Locator anti-pattern in the MyCustomViewPage constructor and my controller will still be testable.
I would then use the following code in partial view:
var messages = MessageProvider.Current.GetMessages()
And the following code in my controllers:
MessageProvider.Current.SetMessage("Message sent successfully.", MessageType.Success);
And in my test fixtures (if I would actually need another implementation):
MessageProvider.SetMessageProvider(otherImplementation);
Do you think this approach makes sense? Any downsides I might be missing?
To anyone who might be looking for the same answer in the future, I decided to use Ambient Context for this because of the reasons I mentioned in the quesiton.

Named binding - MVC3

I'm trying to register to implementations of same interface using named instances
kernel.Bind<IRepository>().To<CachedRepository>().InSingletonScope();
kernel.Bind<IRepository>().To<DbRepository>().InSingletonScope().Named("db");
the idea, is that if I not specify the name then the CachedRepository gets created, if I need a DB oriented one then I'd use the Named attribute, but this miserable fails when a simple object would get created
public class TripManagerController : Controller
{
[Inject]
public IRepository Repository { get; set; } // default Cached repo must be created
public TripManagerController()
{
ViewBag.LogedEmail = "test#test.com";
}
}
the error is
Error activating IRepository More than one matching bindings are
available. Activation path: 2) Injection of dependency IRepository
into parameter repository of constructor of type TripManagerController
1) Request for TripManagerController
Suggestions: 1) Ensure that you have defined a binding for
IRepository only once.
Is there a way to achieve what I want without creating a new interface for BD oriented repositories?
Thx
The [Named] attribute as shown in the wiki should work.
BTW stay away from anything other than ctor injection!
It would seem you cannot do what you're trying, I've just come across the same issue and as well as finding your question I also found this one where the author of Ninject Remo Gloor replied.
https://stackoverflow.com/a/4051391/495964
While Remo didn't explicitly say it couldn't be done his answer was to name both bindings (or use custom attribute binding, amounting the same thing).