We have jax.rs rest application build on Resteasy version 3.1.0.Beta2.
Via extending Application class we add our rest resources and also othre filtres and providers.
One of them is also ResteasyJacksonProvider
#ApplicationPath("")
public class ApplicationConfig extends Application {
final private Set<Class<?>> resources = new HashSet<>();
public ApplicationConfig() {
this.resources.add(ResteasyJacksonProvider.class);
this.resources.add(UserProfileResource.class);
this.resources.add(StatsResource.class);
}
#Override
public Set<Class<?>> getClasses() {
return Collections.unmodifiableSet(this.resources);
}
}
Everythings works fine till I extend it and replace with my custom provider.
#Provider
#Consumes({"application/*+json", "text/json"})
#Produces({"application/*+json", "text/json"})
public class SecureJacksonProvider extends ResteasyJacksonProvider {
}
But now I am getting strange exception for one of the rest calls:
Direct self-reference leading to cycle (through reference chain...
So question is: If there is some reference cycle why it works with default ResteasyJacksonProvider but not with its child.
Note:
I have tried using also JacksonJsonProvider which is parent of ResteasyJacksonProvider and it also thows that exception. - It leads me to think if there can be some problem with dependencies but I found nothing.
Related
I'm trying to migrate from Play 2.3 to 2.5 but I have an issue on replacing the GlobalSettings.OnStart method.
In my old Global class that was extending GlobalSettings, in the onStartMethod I was initialising the Global Config and reading basic things from the DB.
I have created a new class and I m moving the code from the onStart method to the constructor of this one as mentioned in the doc.
https://www.playframework.com/documentation/2.5.x/GlobalSettings
https://www.playframework.com/documentation/2.4.x/PluginsToModules
I'm doing the binding as eagerSingleton from an AbstractModule. The class is correctly started but I keep getting the error:
GlobalBootstrapModule.configure:20 - Binding
OnStartConfig.:35 - Global...on start
Caused by: java.lang.RuntimeException: No EntityManager bound to this thread. Try wrapping this call in JPAApi.withTransaction, or ensure that the HTTP context is setup on this thread.
This is my code:
New class to replace onStart
public class OnStartConfig implements StartConfigInterface{
private final JPAApi jpaApi;
#Inject
public OnStartConfig(Application application, JPAApi jpa){
this.jpaApi = jpa;
Logger.debug("Global...on start");
jpaApi.withTransaction( ()-> {
GlobalConfiguration.aggregationCriteria = AggregationCriterion.getAll();
});
}
The interface I'm extending is just an empty placeholder.
AbstractModule used for the binding:
public class GlobalBootstrapModule extends AbstractModule {
#Override
protected void configure() {
Logger.debug("Binding");
bind(StartConfigInterface.class).to(OnStartConfig.class).asEagerSingleton();
}
}
And I have enabled the module in the application.conf file:
play {
modules {
enabled += modules.GlobalBootstrapModule
}
}
I suppose the problem is due to the lack of HttpContext. Where can I grab it from during the initialisation?
Any help would be hugely appreciated
[EDIT] The problem is with the
register(new ServiceBinder<>(MyService.class));
Jersey generates a warning and ignores the registration for all but the first one (Existing previous registration found for the type); it only considers the type-erased ServiceBinder class to decide there is a conflict.
It looks like I need to use a more sophisticated version of register to get past that issue.
[/EDIT]
In Jersey 1 I was able to use custom injectable providers to inject my objects into both class fields and method parameters, by extending
LazySingletonInjectableProvider
I can't figure out how to port that pattern to Jersey 2 (with hk2 on Tomcat 7). I have read everything I could find on the topic, including Jersey custom method parameter injection with inbuild injection - but I don't want to use a custom annotation, and I am not trying to inject a request parameter.
[EDIT] I made the wrong assumption regarding what works and what doesn't:
Injection into a class field in a ContainerRequestFilter works fine
Injection into a resource, either as class field or method parameter does not work
[EDIT 2]: The InjectionResolver as described below actually doesn't work at all, I have removed it. Jersey already has a ContextInjectionResolver which presumably should take care of the #Context annotation.
I have created and registered an AbstractBinder, and with that class field injection works fine; however method parameter injection doesn't (the binder never gets invoked and the parameter remains null).
I have tried to bind an InjectionResolver but that didn't help either.
Any suggestion on how to make this work would be greatly appreciated... here is the current code:
The HK2 binder:
public class ServiceBinder<T> extends AbstractBinder
{
private final Factory<T> _factory;
private final Class<? extends T> _clazz;
public OsgiServiceBinder(Class<T> clazz)
{
_factory = new ServiceFactory<>(clazz);
_clazz = clazz;
}
protected void configure()
{
bindFactory(_factory).to(_clazz); //.in(RequestScoped.class);
bind(ServiceInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<Context>>() { })
.in(PerLookup.class);
}
}
The injection resolver:
public class ServiceInjectionResolver<T> implements InjectionResolver<Context>
{
private Class<T> _clazz;
public OsgiServiceInjectionResolver(Class<T> clazz)
{
_clazz = clazz;
}
public Object resolve(Injectee injectee, ServiceHandle<?> root)
{
if (_clazz.getCanonicalName().equals(injectee.getRequiredType().getTypeName())) {
return Framework.getService(_clazz);
}
return null;
}
public boolean isConstructorParameterIndicator()
{
return false;
}
public boolean isMethodParameterIndicator()
{
return true;
}
}
The JAX-RS registration:
public class MyApplication extends Application
{
public MyApplication()
{
registerClasses(<resource classes>);
register(new ServiceBinder<>(MyService.class));
}
}
The resource class:
#Path("/schedules")
public class SchedulesResource
{
#Context UriInfo _uriInfo;
// This injection works fine, _service1 is properly initialized
#Context MyService _service1;
#PUT
#Consumes({MediaType.APPLICATION_JSON})
#Path("{jobGroup}/{jobName}")
public Response putSchedule(#Context MyService service2,
...)
{
// The injection of service2 doesn't work...
}
}
The Factory class:
public class ServiceFactory<T> implements Factory<T>
{
private Class<T> _clazz;
protected ServiceFactory(Class<T> clazz)
{
_clazz = clazz;
}
public T provide()
{
return Framework.getService(_clazz);
}
}
public void dispose(T t)
{
}
}
pok
The problem was actually with Jersey component registrations.
Even though I was registering binder instances, Jersey was checking the class (ServiceBinder) and discarding all but the first registration (WARN: existing registration found for the type).
This seems a bit bogus given I am registering instances, and I wish Jersey would fail with an error rather than log a warning when failing to register a component, but the solution is to simply change the registration pattern slightly:
// Doesn't work
register(new ServiceBinder<>(MyService1.class));
register(new ServiceBinder<>(MyService2.class));
// Works like a charm
register(new ServiceBinder(MyService1.class, MyService2.class));
where obviously the ServiceBinder is adjusted to call bindFactory for each supplied service.
i am going to continue to express my seemingly endless missunderstanding in EJBs:
I am using JBoss 8 (Wildfly 8.1) as my Applicationserver.
I am currently building a workaround for the Problem, that Inpustreams cannot be passed to remote EJB via RMI (which makes absolute sense once i thought about it).
I i must not replace the existing Resources Interface (writing an Inpustream to a File) I build following 3 Projects as a solution:
Interfaces (library included in both EARs):
com.package.ejb
public interface StorageAdapter extends Serializable{
String store(Inpustream is); (//returns an id
Inputstream load(String id);
}
public interface StorageAdapterProvider{
StorageAdapter provide();
}
Persistence-EAR
com.package.impl
public class FileSystemStorageAdapter implements com.package.ejb.Storageadapter {
//implementation, writing to locally mounted path in filesystem...
}
com.package.impl
#Singleton
#Remote(com.package.ejb.StorageAdapterProvider.class)
public class StorageAdapterProviderBean implements com.package.ejb.StorageadapterProvider {
public StorageAdapter provide() {
return new FileSystemStorageAdapter();
}
}
Business-EAR
com.package.business
public class StorageProvider {
#EJB(looklup = "java:global/Persistence-EAR/StorageAdapterProviderBean!com.package.ejb.StorageAdapterProvider"
private StorageAdapterProvider provider;
#Produces
public StorageAdapter getStorageAdapter() {
return provider.provide();
}
}
I then use #Inject StorageAdapter storageAdapter; to get an instance of the Storageadapter-implementation.
Business-EAR/Storageprovider then throws a ClassCastException, telling me that com.package.impl.FileSystemStorageAdapter cannot be cast to com.package.ejb.StorageAdapter
i added some logging to the EJB
com.package.impl
#Singleton
#Remote(com.package.ejb.StorageAdapterProvider.class)
public class StorageAdapterProviderBean implements com.package.ejb.StorageadapterProvider {
public StorageAdapter provide() {
StroageAdapter ret = new FileSystemStorageAdapter();
logger.info("EJB: RETURNING Stortage adapter");
logger.info(" is of type:"+ret.getClass().getName());
logger.info(" is Storageadapter: "+ (ret instanceof StorageAdapter));
logger.info(" is FileSystemStorageAdapter: "+ (ret instanceof FileSystemStorageAdapter));
return ret;
}
}
and it correctly prints:
EJB: RETURNING Stortage adapter
is of type:com.package.impl.FileSystemStorageAdapter
is Storageadapter: true
is FileSystemStorageAdapter: true
Further investigation shows, that the Exception is thrown while the container is Wrapping the "ret" Object, as i also get the Exeption if i chnage the #Provides implementation to:
Object o = provider.provide();
Is it impossible to return an Interface type from an EJB?
What am i missing?
Does Business-EJB need to know the implementing Classes? - Wouldn't a ClassNotFound Exception make more sense in this case?
Thanks in advance!
EDIT:
My Packaging looks as follows:
Persistence.ear
-lib/Interfaces.jar
-StorageAdapter
-Storageprovider
-persistence_ejb.jar
-FileSystemStorageAdapter
-StorageAdapterProviderBean
Business.ear
-lib/Interfaces.jar
-StorageAdapter
-Storageprovider
-business_ejb.jar
-StorageProvider
-web.war
-Jaxrsres
The Jaxrsres is the one having a Storageadapter Injected via #Inject
I am deploying these 2 wars to a JBoss Wildlfly 8.1 Server.
I did not make any relevant changes to the configuration - so all the other Point you requested are defaults as far as I understand.
EDIT2:
It somewhat defeats the purpose, but it works if i add the Persistence.ear/persistence_ejb.jar to the libraries of Business.ear.
Business.ear
-lib
-Interfaces.jar
-StorageAdapter
-Storageprovider
-persistence_ejb.jar
-FileSystemStorageAdapter
-StorageAdapterProviderBean
-business_ejb.jar
-StorageProvider
-web.war
-Jaxrsres
This is obviously not what I want though :/
The main Point is, i want to be able to redeploy Persistence.ear with, say, "DatabaseStorageAdapter", without touching business.ear.
The "Dream" is to Provide the Storageadapter as an EJB Directly - but as the Interface is fixed and needs an InputStream, this cannot be done.
#Path("/test")
public class MyClass {
#GET
public Response response() {
// Generating some expensive object here.
}
Right now I load the data into arrays etc inside the "response" function, but I want to do it before the query is even made. This way, I want to avoid reloading the data every time a a query is made. How do I achieve this?
This depends on your framework. Are you using the reference implementation Jersey? Jersey comes bundled with HK2 automatically. Then you could add
#Path("/test")
public class MyClass {
#Inject
private MyState stateful;
// here comes your code...
}
to your resource. Of course, you would still need to configure what to inject into this field. With HK2, you use an AbstractBinder for this purpose:
class MyBinder extends AbstractBinder {
private final MyState stateful;
public MyBinder (MyState stateful) {
this.stateful = stateful;
}
#Override
protected void configure() {
bind(stateful).to(MyState.class);
}
}
Finally, you need to add this binder on the application's setup. For this purpose, JAX-RS Application object can be queried for singletons. Simply add the required instance to the application such that it is returned by Application#getSingletons as here:
class MyJaxRSApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
return Collections.singletonSet(MyClass.class);
}
#Override
public Set<Object> getSingletons() {
return Collections.singletonSet(new MyBinder(new MyStateImpl()));
}
}
You can now run your application where MyStateImpl is always injected into MyClass.
Jersey (and JAX-RS in general) allows simple dependency injection as follows:
#Path("/")
public class MyResource {
#Context private Application application;
...
}
Jersey first creates the class, then it binds dependencies to it. Is this a mechanism I can re-use for instances whose lifecycle I control entirely?
For example, consider an interface with some unknown implementations.
public interface MyInterface {
public boolean isHappy();
}
Suppose I have a list of these in one of my provider singletons, for example, an ExceptionMapper. It would be initialized in some subclass of Application.
#Provider
public class MyExceptionMapper implements ExceptionMapper<Exception> {
private List<MyInterface> list;
public ExceptionMapper(List<MyInterface> list) {
this.list = list;
}
#Override
public Response toResponse(Exception e) {
for (MyInterface item : list) {
// Manually bind dependencies here?
if (item.isHappy()) {
return Response.ok("Nope, no errors here. Promise.").build();
}
}
return Response.serverError().build();
}
}
And finally, suppose there's a specific implementation of this interface that needs access to the Application:
public class MyImplementation implements MyInterface {
#Context private Application application; // Can't do this
#Override
public boolean isHappy() {
MyApplication myApp = (MyApplication) application;
return myApp.shouldIgnoreExceptions(); // NullPointerException
}
}
Is there a way to bind contexts for all of the implementations of my interface? Or do I need to find a way to get Jersey to manage all implementations (by making them providers)? Or must I resort to CDI to perform dependency injection?
Note that I'm using Jersey 1.17.1, and I'd like to avoid defining any particular dependency as being part of the interface.
The JAX-RS way is to implement your own ContextResolver for MyInterface. Then you can manage the implementation of the contexts inside the context resolved. Context resolver is provider and is managed by Jersey, but not the MyInterface implementations.