I have a base collection of REST resources annotated to correspond to certain paths.
Psuedo code:
#Path("/collection")
class Stuff {
#Path("/{id}")
#GET
public String get(#PathParm("id") int id) {
return String.format("Item #%d". id);
}
}
Now, I need to add a sub resource to this collection without changing the class Stuff, but adding code like below doesn't work:
#Path("/collection/{id}")
class StuffPlugin {
#Path("/extra")
#GET
public String extra(#PathParm("id") int id) {
return String.format("Extra info about item #%s", id);
}
}
This used to work in RESTeasy 2.3 but now, upgrading to version 3.0.4 the latter seems to shadow the Stuff class when RESTeasy is looking for possible path matches and thus break the whole structure of my app.
How would this be accomplished in RESTeasy 3?
Thank you
PS
I am adding the provider classes programmatically like below and everything that doesn't have colliding base paths is working fine.
public class EntryPoint extends Application {
public EntryPoint() {}
#SuppressWarnings("serial")
#Override
public Set<Class<?>> getClasses() {
return new HashSet<Class<?>>() {
{
add(Stuff.class);
add(StuffPlugin.class);
}
}
}
}
RestEasy 3.x is based on JAX-RS 2.0 which is a new specification update in JAX-RS.
The developer who maintains the RestEasy has already written a blog post about weird path matching algorithm !
http://bill.burkecentral.com/2013/05/29/the-poor-jax-rs-request-dispatching-algorithm/
In your case it might have worked earlier as RestEasy was implementing the old spec which was not so strict about the implementation of the matching algorithm, which may not work now..
Better be you reflector the code and define the resources appropriately !
Related
I am working with AspectJ at the moment.
I seperated AspectJ code in a dependency.
Within that dependency everything works as intended.
But as soon as I import it in another project only some functionality does not work anymore.
When using the defaultImpl of #DeclareParents, the interface is shown within the compiled code but not the default Implementation.
Here is my code to show what I mean (every code snippet is its own File):
AspectJ code:
public interface IAspect
{
String hello();
}
public class IAspectDefaultImpl implements IAspect
{
#Override
public String hello()
{
return "hello";
}
}
#Aspect
public class AspectJ
{
#DeclareParents(value = "#SomeAnnotation*", defaultImpl = IAspectDefaultImpl.class)
private IAspect implementedInterface;
}
Target Class in a different project:
#SomeAnnotation
public class MyClass
{
private final int myValue;
public MyClass(final int wert)
{
this.myValue = wert;
}
public int getMyValue()
{
return myValue;
}
}
Maven throws me:
The type MyClass must implement the inherited abstract method IAspect.hello()
Which implies that it works partially.
When looking at the decompiled .class files the targeted Class does in fact implement IAspect.
The method defined in IAspectDefaultImpl is still missing tho.
My pom is set up like in this example.
I am not sure where I should start to look for errors.
Any help is apreciated.
Thanks for the MCVE. But hey, you don't use Git in order to commit 7z or ZIP archives, you ought to commit source code. I forked your project and fixed that, restructured and simplified your POMs and also fixed the main problem.
See my pull request and the commits in it for further details.
Concerning your problem, I can confirm that it occurs if you use #DeclareParents the way you do in an aspect library.
Actually, according to AspectJ maintainer Andy Clement there are certain problems with #DeclareParents when using it to provide parent interfaces + implementations in annotation style. The native AspectJ syntax via declare parents is not affected by that, but for annotation-style syntax Andy provided an alternative called #DeclareMixin, see the AspectJ manual. There he mentions that he is even considering to deprecate the defaultImpl argument of #DeclareParents in favour of #DeclareMixin.
So my bugfix (or workaround) for your problems is to actually replace
#DeclareParents(value = "#de.example.aspect.SomeAnnotation *", defaultImpl = IAspectDefaultImpl.class)
private IAspect implementedInterface;
by
#DeclareMixin("#de.example.aspect.SomeAnnotation *")
public static IAspect createIAspectImplementation() {
return new IAspectDefaultImpl();
}
This works with aspect libraries.
I will discuss with Andy about whether it makes sense to file a bug ticket for your problem or if he won't fix it anyway because there is a viable and recommended alternative.
While working on a .NET project I come across a library MediatR which made CQRS and Commands simple to implement. I really like using commands and commands handlers as I've worked on far too many projects that have giant procedural style service classes that inject way to many dependencies making unit testing painful. I am looking for something similar to MediatR for Spring + Java. Essentially I would like to inject a single dependency into the controller class and have it delegate commands to the appropriate command handler. I provided a few snippets of what MediatR looks like below. I prefer the way mediator does it as injecting the CommandHandlers into the controller class can lead to the same issue with the class having tons of dependencies injected.
I've came across this library but it seems more like a side project that something that is production ready. https://github.com/sleroy/spring-cqrs-arch. I am aware of the Axon framework, but I'm not looking to go full blown event sourcing at this point. Are there any libraries out there already for this that maybe I'm haven't stumbled across yet? I suppose I could just use the Guava EventBus.
Below is a C# example of what MediatR usage looks like.
Controller
namespace DAB.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PersonController : ControllerBase
{
private readonly IMediator mediator;
public PersonController(IMediator mediator)
{
this.mediator = mediator;
}
// GET api/values
[HttpPut("{id}/changename")]
public async Task<ActionResult> ChangeName([FromBody] ChangeNameCommand command)
{
await this.mediator.Send(command);
return Ok();
}
}
}
Command
public class ChangeNameCommand: IRequest<bool>
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
CommandHandler
public class ChangeNameHandler: IRequestHandler<ChangeNameCommand, bool>
{
public Task<bool> Handle(ChangeNameCommand request, CancellationToken cancellationToken)
{
Console.WriteLine($"Changing name to {request.FirstName} {request.LastName}");
return Task.FromResult(true);
}
}
Check out PipelinR. It's 15KB, zero-dependency library, with a nice Spring and Spring Boot integration.
if you are still looking for a similar library, I made a library that works similarly with mhinze/ShortBus. You may check it at https://github.com/kazupooot/shortbus. Currently it supports single handler request/response message.
i have two independent projects Basic and Extension with following setup
Project A:
class Handler {
public void handle(){
...
}
}
Project B
import Handler; //from Proejct A
class SomeClass{
someMethod() {
handle(); //dependency to Project As class with handle method
}
}
So the problem is the dependecy to the handle method which exists at Project A but not at compile time on Project B.
The final step is to have build Project Extension as a jar and import it inside Project Basic.
Ofc the compiler will give me error when i build Project B since the handle is not known at compile time.
For this issue i need a solution:
Either: Tell java that the missing code (import class with handle method) will be there at running time.
Or maybe Dependency Injection due to a factory pattern.
I am known to the factory pattern, but i don't understand how it could help me in this situation.
Or another solution.
Can you help me?
Neither of these are valid Java - won't compile. The proper keyword is "class", not "Class".
You have to provide it at compile time once you get it right - you have no choice. No way around it.
Maybe you should look at the Java JDK and follow the example in the java.sql package: Interfaces. Connection, ResultSet, Statement, etc. are all interfaces so vendors can provide their own implementations. Users only deal with interfaces.
Your GenericHandler should be an interface that you provide to clients. They add their implementations and add their JAR file containing the custom implementation at runtime.
Basic interface that all extensions implement:
public interface GenericHandler {
void genericHandle();
}
Extension code:
import GenericHandler;
public class Extension implements GenericHandler {
public void genericHandle() {
// Do something useful here
}
}
The factory pattern works only if you provide a finite, closed set of implementations:
public class GenericHandlerFactory {
private final GenericHandlerFactory instance = new GenericHandlerFactory();
private GenericHandlerFactory() {}
public GenericHandler getInstance() { return this.instance; }
public GenericHandler createHandler(Class genericHandlerClass) {
GenericHandler result = null;
// Code to create the GenericHandler you want.
return result;
}
}
If users can extend your interface without your knowledge then a factory can't work; you have to stick to the JDBC example.
I am building an Android app. Now, I have a source code for API #1, I should get it adapted for API #2. Then I will publish the both versions for API #1 and API #2 in different packages. I can't use something like values-en, because both versions can be used worldwide. Also, the user may not have choice.
As the new version will use same UI and DB logic, (and because now the code is erroneous,) I don't want to separate the code. If i were coding in c or c++, I must use #ifdef and Makefile. However, I'm in Java. It's possible to run the API-dependent code by determining the package name in runtime, but it's somewhat weird.
I think I can use annotations. What I expect is:
package foo.app;
public class API {
public boolean prepare() { ... }
#TargetPlatform(1)
public void open() { ... }
#TargetPlatform(2)
public void open() { ... }
}
and use only one of them. Also, this is good:
package foo.app;
public class R {
#TargetPlatform(1) com.example.foo.app.R R;
#TargetPlatform(2) net.example.foo.app.R R;
}
Just defining an annotation is simple. What I don't know is, how can I exclude unused duplicates from build or execution, or so on? If the work can be done in this way, I can do anything.
You cannot use annotations for that.
It would be better to hide the implementation specific classes behind an interface.
public interface Api {
boolean prepare();
void open();
}
To create a Api instance use a factory class:
public class ApiFactory {
public static Api createApi() {
if(isTargetPlatform1())
return new com.example.foo.app.Api();
else
return new net.example.foo.app.Api();
}
private boolean isTargetPlatform1() {
// determine the current platform, e.g. by reading a configuration file
}
}
In all other places you only refer to the Api interface and ApiFactory class.
Use it like that:
Api api = ApiFactory.createApi();
api.open();
// ...
A more advanced solution would be to use dependency injection.
With RESTEasy I've implemented a subclass of Application to provide a list of singleton resources. Is there a way to add another singleton dynamically later on? I've not found a way to do it from the API docs.
I have not tried this myself, but I found a blog post where this is described:
http://sarbarian.wordpress.com/2010/03/07/resteasy-and-osgi-perfect-match/
During deployment, RESTEasy puts it's registry in the servlet context. The idea suggstested in the blog, is that you fetch the registry from the servlet context, and then add your resource class.
Something like this:
import org.jboss.resteasy.spi.Registry;
Object resource = new MyService();
Registry registry = (Registry) context.getAttribute(Registry.class.getName());
registry.addSingletonResource(resource);
I have tried this myself, and although it was nerve-wracking, it works great. We've got an infrastructure where several independent projects (plug-ins) are imported and loaded by our main application, and we wanted to include access to them in our existing RestEasy API (and Swagger documentation).
We originally hard-coded the class-loading into our main Rest Application class, which required all of the plug-ins to be displayed at all times in our API. To avoid that and to re-instate the independence of those projects (all, some, or none may be included at any given time), we created dynamic methods that return the feature/target class itself, which is loaded during the bootstrap phase of the RestEasy framework. It worked like a charm.
Within our Rest Application class, we implemented it as follows:
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(mainAPIStuff.class);
classes.add(plugin1.class);
classes.add(plugin2.class);
classes.add(plugin3.class);
.
.
.
return classes;
}
That was the old way. The new way was to loop through all of our plugins and return a hashSet of the classes that the plugins provide:
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(mainAPIStuff.class);
classes.addAll(pluginsHelper.getClasses());
return classes;
}
The pluginsHelper has sundry shared plugin methods and administrative tools, like getClasses(), which does basically this:
public static Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
// Probe plugins for their Rest Class implementation
List plugins = getCurrentlyInstalledPluginsFromOurSystem();
for (PluginObject plugin : plugins) {
Class<?> clazz = plugin.getPluginRestClass();
if (clazz != null) {
classes.add(clazz);
}
}
return classes;
}
RestEasy builds the Rest targets dynamically when any target is called, so all of the plugin installation, startup, config has already completed and the system is in the correct state before it is called. This is very valuable to understand, since then you can do all of the RestEasy class manipulation and loading at call time.
I use Reateasy with Undertow in embedded environment, where I manually instantiate ResteasyDeployment, and register Resource class is really easy, see code snippet blow:
UndertowJaxrsServer undertowJaxrsServer = new UndertowJaxrsServer();
ResteasyDeployment resteasyDeployment = new ResteasyDeployment();
undertowJaxrsServer.start();
resteasyDeployment.start();
final DeploymentInfo undertowDeployment =
undertowJaxrsServer
.undertowDeployment(resteasyDeployment)
.setContextPath("/abc")
.setDeploymentName("TEST")
.setClassLoader(Thread.currentThread().getContextClassLoader());
undertowJaxrsServer.deploy(undertowDeployment);
resteasyDeployment.getRegistry().addSingletonResource(new ResourceApiImpl());