I have pretty the same question as it has been asked here (Exposing link on collection entity in spring data REST). But nothing from that topic helps me to add custom link to collection call.
#Component
public class EventListResourceProcessor implements ResourceProcessor<Resources<Event>> {
#Autowired
private RepositoryEntityLinks entityLinks;
#Override
public Resources<Event> process(Resources<Event> events) {
events.add(entityLinks.linkToCollectionResource(Event.class).withRel("events"));
return events;
}
}
process method is never called in this case.
I need to call http://localhost:8080/event and get the following JSON with my_custom_link under _links section:
{
"_embedded": {
"event": [
{
"id": "1",
"name": "Updated event"
}]
},
"_links": {
"self": {
"href": "http://localhost:8080/event"
},
"profile": {
"href": "http://localhost:8080/profile/event"
},
"my_custom_link": {
"href": "http://localhost:8080/custom/"
}
},
"page": {
"size": 20,
"totalElements": 4,
"totalPages": 1,
"number": 0
}
}
}
Could you please advise me?
Thanks in advance!
I was in a similar situation to your question: I had read through the question/answers you linked and found none of them could solve the problem. Here was the eventual answer to my problem:
#Component
public class MyResourceProcessor implements ResourceProcessor<Resource<MyInterface>> {
#Autowired
private EntityLinks entityLinks;
#Override
public Resource<MyInterface> process(Resource<MyInterface> event) {
event.add(entityLinks.linkForSingleResource(MyClass.class, event.getContent().getId()).slash("custom").withRel("custom"));
return event;
}
}
This process method was called for each Resource in the relevant collection of Resources being returned. The MyInterface interface and MyClass class should be replaced with whatever you end up needing, but it was required to be written that way to get this to work. Here are the steps I used to get the process method called correctly and to determine the MyInterface type.
I created a process method that simply took ResourceSupport as the parameter. I created a breakpoint in the code and inspected what underlying class was extending ResourceSupport. In my case it was PersistentEntityResource. This explained why using Resource<MyClass> or Resources<MyClass> were never causing the process method to be called: PersistentEntityResource extends Resource<Object>.
I updated the process method take PersistentEntityResource as the parameter. This caused the process method to be called for more than my intended changes. I once again used the breakpoint to inspect the PersistentEntityResource object with the intent of discovering what class could be found in the Resource<Object> that it extended. I discovered it was a Proxy class, and could not be cast to MyClass as I had desired.
I followed the answer found here to find out more information about the Proxy class: https://stackoverflow.com/a/3344386/1417690. While debugging, I discovered the list of interfaces that helped define this class. One of them was of type MyProjectionInterface. I now knew that the reason I couldn't use Resource<Portal> was because it was actually a Resource<MyProjectionInterface>.
I had three different Projections that I needed to handle. Instead of creating three separate ResourcePorcoessors I created the MyInterface and had all three of my projection interfaces extend it. The MyInterface only contained a Long getId() method which all of the projections already supported anyway.
I updated my code to use Resource<MyInterface> and added the linkForSingleResource using MyClass (that all of the projections relate to) and the getId() method I had defined in MyInterface. This successfully added the desired link to each of the resources being returned.
Hopefully these steps help others discover how to determine what type to use as the parameter for the process method.
Because I faced the same issue and I hoped an answer here. The solution is to declare a bean ResourceProcessor implementing the right generic type which extends ResourceSupport.
In our case for a paginable resource, the right ResourceSupport is PagedResources<Resource<MyInterface>> as the following sample :
#Bean
public ResourceProcessor<PagedResources<Resource<Supplier>>> pageableSupplierProcessor() {
return new ResourceProcessor<PagedResources<Resource<Supplier>>>() {
#Override
public PagedResources<Resource<Supplier>> process(PagedResources<Resource<Supplier>> resources) {
Method registerMethod;
try {
registerMethod = SupplierRegistrationController.class.getMethod("register",
RegistrationRequest.class);
Link registerLink = linkTo(registerMethod, new RegistrationRequest()).withRel("register");
resources.add(registerLink);
return resources;
} catch (NoSuchMethodException | SecurityException e) {
throw new IllegalStateException(e);
}
}
};
}
Related
With Autofac, what is the proper way to register types or declare dependencies for this type of circular graph?
public interface IComponent
{
void DoSomething();
}
public class AComponent: IComponent
{
...
}
public class BComponent: IComponent
{
...
}
public class CompositeComponent: IComponent
{
public CompositeComponent(IEnumerable<IComponent> components)
{
this.components = components;
}
public void DoSomething()
{
foreach(var component in components)
component.DoSomething();
}
}
The end goal would be that CompositeComponent be the default registration of IComponent and simply pass down calls to all other implementations.
I am gathering that the intent of the question is that you have some implementations of IComponent and you have some sort of CompositeComponent that also implements IComponent. CompositeComponent needs all of the registered IComponent instances except itself otherwise it creates a circular dependency.
This whole thing overlaps pretty heavily with one of our FAQs: "How do I pick a service implementation by context?"
You have some options. In order of my personal recommendation:
Option 1: Redesign the Interfaces
There are actually two concepts going on here - the notion of an individual handler and the notion of a thing that aggregates a set of individual handlers.
Using less generic terms, you might have an IMessageHandler interface and then something that passes a message through the set of all IMessageHandler implementations, but that thing that aggregates the handlers and deals with errors and ensuring the message is handled only by the right handler and all that... that isn't, itself, also a message handler. It's a message processor. So you'd actually have two different interfaces, even if the methods on the interface look the same - IMessageHandler and IMessageProcessor.
Back in your generic component terms, that'd mean you have IComponent like you do now, but you'd also add an IComponentManager interface. CompositeComponent would change to implement that.
public interface IComponentManager
{
void DoSomething();
}
public class ComponentManager : IComponentManager
{
public ComponentManager(IEnumerable<IComponent> components)
{
this.components = components;
}
public void DoSomething()
{
foreach(var component in components)
component.DoSomething();
}
}
Option 2: Use Keyed Services
If you won't (or can't) redesign, you can "flag" which registrations should contribute to the composite by using service keys. When you register the composite, don't use a key... but do specify that the parameter you want for the constructor should resolve from the keyed contributors.
builder.RegisterType<AComponent>()
.Keyed<IComponent>("contributor");
builder.RegisterType<BComponent>()
.Keyed<IComponent>("contributor");
builder.RegisterType<CompositeComponent>()
.As<IComponent>()
.WithParameter(
new ResolvedParameter(
(pi, ctx) => pi.Name == "components",
(pi, ctx) => ctx.ResolveKeyed<IEnumerable<IComponent>>("contributor")));
When you resolve IComponent without providing a key, you'll get the CompositeComponent since it's the only one that was registered that way.
Option 3: Use Lambdas
If you know up front the set of components that should go into the composite, you could just build that up in a lambda and not over-DI the whole thing.
builder.Register(ctx =>
{
var components = new IComponent[]
{
new AComponent(),
new BComponent()
};
return new CompositeComponent(components);
}).As<IComponent>();
It's more manual, but it's also very clear. You could resolve individual constructor parameters for AComponent and BComponent using the ctx lambda parameter if needed.
I want to achieve two goals:
I want my model to be loaded every time from the DB when it's in a life-cycle (for every request there will be just one request to the DB)
I want my model to be attached dynamically to the page and that wicket will do all this oreable binding for me
In order to achieve these two goals I came to a conclusion that I need to use both CompoundPropertyModel and LoadableDetachableModel.
Does anyone know if this is a good approach?
Should I do new CompoundPropertyModel(myLoadableDetachableModel)?
Yes, you are right, it is possible to use
new CompoundPropertyModel<T>(new LoadableDetachableModel<T> { ... })
or use static creation (it does the same):
CompoundPropertyModel.of(new LoadableDetachableModel<T> { ... })
that has both features of compound model and lazy detachable model. Also detaching works correctly, when it CompoudPropertyModel is detached it also proxies detaching to inner model that is used as the model object in this case.
I use it in many cases and it works fine.
EXPLANATION:
See how looks CompoundPropertyModel class (I'm speaking about Wicket 1.6 right now):
public class CompoundPropertyModel<T> extends ChainingModel<T>
This mean, CompoundPropertyModel adds the property expression behavior to the ChainingModel.
ChainingModel has the following field 'target' and the constructor to set it.
private Object target;
public ChainingModel(final Object modelObject)
{
...
target = modelObject;
}
This take the 'target' reference to tho object or model.
When you call getObject() it checks the target and proxies the functionality if the target is a subclass of IModel:
public T getObject()
{
if (target instanceof IModel)
{
return ((IModel<T>)target).getObject();
}
return (T)target;
}
The similar functionality is implemented for setObject(T), that also sets the target or proxies it if the target is a subclass of IModel
public void setObject(T object)
{
if (target instanceof IModel)
{
((IModel<T>)target).setObject(object);
}
else
{
target = object;
}
}
The same way is used to detach object, however it check if the target (model object) is detachable, in other words if the target is a subclass if IDetachable, that any of IModel really is.
public void detach()
{
// Detach nested object if it's a detachable
if (target instanceof IDetachable)
{
((IDetachable)target).detach();
}
}
I need to modify an existing web app to use Castle.Windsor as IOC container. It was originally developed with StructureMap.
I am stuck with the following problem.
Lets say I have registered a couple of interfaces and their corresponding implementations:
IFoo -> Foo
IBar -> Bar
Calling container.Resolve<IFoo>() or container.Resolve<IBar>() works just fine. This means that the services are registered correctly.
I have a Web Api class with dependencies on other services, such as IFoo
public class BadRequestErrorHandler : HttpErrorHandler
{
// services
public BadRequestErrorHandler(IFoo foo) {...} // has dependency on IFoo
}
In StructureMap I can call:
var test = ObjectFactory.GetInstance<BadRequestErrorHandler>();
this will resolve the IFoo dependency.
Now this does not work with windsor.
How can this be achieved with windsor?
Thanks!
* EDIT *
I was just able to make it work by explicitely registering the BadRequestErrorHandler.
container.Register(Component.For<BadRequestErrorHandler>());
I am just hoping there is a better way to achieve this, that does not involve registering classes that have dependencies. I have a bunch of them...
* EDIT 2 **
To ease the pain, I added a special method to deal with these concrete types.
public T GetInstanceWithAutoRegister<T>()
{
if (container.Kernel.GetHandler(typeof(T)) == null)
{
container.Register(Component.For<T>());
}
return container.Resolve<T>();
}
public object GetInstanceWithAutoRegister(Type pluginType)
{
if (container.Kernel.GetHandler(pluginType) == null)
{
container.Register(Component.For(pluginType));
}
return container.Resolve(pluginType);
}
not ideal, but at least better than having to explicetly register each type. Hope someone has a better solution
You can achieve what you want by registering an ILazyComponentLoader which is a hook that gets called by Windsor as a "last resort" when a component cannot be resolved.
In your case, the implementation would probably look somewhat like this:
public class JustLetWindsorResolveAllConcreteTypes : ILazyComponentLoader
{
public IRegistration Load(string key, Type service)
{
return Component.For(service);
}
}
-and then it should be registered as such:
container.Register(Component.For<ILazyComponentLoader>()
.ImplementedBy<JustLetWindsorResolveAllConcreteTypes>());
You can read more about it in the docs.
How do I register IPetFactory<TPet> to be resolved with DefaultPetFactory<TPet> where TPet can be any class based on Pet in the example below?
I'd like to be able to resolve IPetFactory<Dog> with DefaultPetFactory<Dog>.
I've just found examples using BasedOn where the Factory itself is based on a class, not the generic argument.
class Pet
{
public string Name { get; set; }
}
class Fish : Pet {}
class Dog : Pet {}
class Cat : Pet { }
interface IPetFactory<TPet> where TPet : Pet;
class DefaultPetFactory<TPet> : IPetFactory<Pet> where TPet : Pet
{
// default implementation
}
My real implementation has a lot of classes based on Pet so I'm looking for a more generic approach than just calling register on each of them.
EDIT:
I found out the problem wasn't what I thought it was. It was due to the generic arguments and an exception of “the arity of the generic type definition” which caused my problems.
And I over-simplified my example. In my real implementation I have to generic arguments and it turns out Windsor need the the same generic parameters to be able to resolve the type.
If I do like this it won't work.
class Owner
{
}
class DefaultPetFactory<TPet> : IPetFactory<Owner, TPet> where TPet : Pet
{
// default implementation
}
If I do like this it will:
class DefaultPetFactory<TOwner, TPet> : IPetFactory<TOwner, TPet>
where TOwner : Owner
where TPet : Pet
{
// default implementation
}
If anyone has a better solution to this, preferably with the registrations it's appreciated. I don't like to change my classes to make the registration work.
(For the updated question)
There is a ticket in Windsor's issue tracker to support scenarios like that (feel free to vote for it), but in general this is something very hard to implement... generically (no pun intended), and as far as I know no container currently supports it.
In Windsor 3 you can workaround it by implementing a new interface called IGenericImplementationMatchingStrategy doing roughly the following (untested, I'm writing this from memory):
public class PetMatcher: IGenericImplementationMatchingStrategy
{
public Type[] GetGenericArguments(ComponentModel model, CreationContext context)
{
if (SomePreconditionToMakeSureThatsReallyTheScenarioDescribedAbove() == false )
{
return null;// which will fallback to default behaviour
}
// implementation needs just one generic arg, second of two the interface has
return new[]{ context.GenericArguments[1] };
}
}
You then register this as follows:
Container.Register(
Classes.FromAssemblyContaining(typeof(IPetFactory<,>)).BasedOn(typeof(IPetFactory<,>))
.WithServiceBase()
.Configure(
c => c.ExtendedProperties(
Property.ForKey(ComponentModel.GenericImplementationMatchingStrategy)
.Eq(new PetMatcher()))));
I'm new to ASP.NET MVC and can't figure this out. Working through the Nerdinner example from Professional ASP.NET MVC 2, I copied the PaginatedList helper class and decided to improve it so the forward and back links could be generated by a method within the class instead of writing them out in every view page. I copied this from the view that it was in, Index.aspx:
if (Model.HasPreviousPage)
{
Response.Write(Html.RouteLink("<<<", "Users", new { page=(Model.PageIndex-1) }));
}
And used it to create this method within Helpers\PaginatedList.cs:
public string NavLinks()
{
if (HasPreviousPage)
{
return Html.RouteLink("<<<", "Users", new { page=(PageIndex-1) });
}
}
(HasPreviousPage is a simple method within PaginatedList.)
Straight away it complains that "The name 'Html' does not exist in the current context, so I modified it to take a parameter:
public string NavLinks(HtmlHelper Html)
Now I get "'System.Web.Mvc.HtmlHelper' does not contain a definition for 'RouteLink' and no extension method 'RouteLink' accepting a first argument of type 'System.Web.Mvc.HtmlHelper' could be found (are you missing a using directive or an assembly reference?)".
According to Microsoft documentation on LinkExtensions.RouteLink method, "In Visual Basic and C#, you can call this method as an instance method on any object of type HtmlHelper". Do they lie?
Help!
If your trying to make this an HtmlHelper just change
public string NavLinks(HtmlHelper Html)
{
if (HasPreviousPage)
{
return Html.RouteLink("<<<", "Users", new { page=(PageIndex-1) });
}
}
to
using System.Web.Mvc;
using System.Web.Mvc.Html;
public static MvcHtmlString NavLinks(this HtmlHelper html, hasPreviousPage)
{
if (hasPreviousPage)
{
return html.RouteLink("<<<", "Users", new { page=(PageIndex-1) });
}
}
All of the HtmlHelpers contained within Mvc are static methods and also they return an MvcHtmlString in Asp.net MVC 2. This will be an extension method for the class HtmlHelper. After adding those references to your code file that contains this extension methods you should see the RouteLink method inside of there.
#DeathBedMotorcade
That helped, but I had to change a few things.
The method can't be static because it needs to access properties of the object (part of same class, PaginatedList), specifically the HasPreviousPage method and the PageIndex variable. Then it gave the error "Extension method must be static". Removing the "this" keyword fixed that. So I have:
public MvcHtmlString NavLinks(HtmlHelper html)
{
if (HasPreviousPage)
{
return html.RouteLink("<<<", "Users", new { page=(PageIndex-1) });
}
if (HasNextPage)
{
return html.RouteLink(">>>", "Users", new { page=(PageIndex+1) });
}
return null;
}
And in the view:
Response.Write(Model.NavLinks(Html))
And that works, though I don't fully understand all the reasons why it didn't before.
"using System.Web.Mvc.Html" was key although I thought I'd tried that at some point; probably before realising the item "Html" (an HtmlHelper object that is implicitly passed to the view?) needed to be passed in. VS usually prompts for missing Using statements but didn't this time.
Thanks.