How to bind a object with Guice in Dropwizard? - java

I want to use a bind object in my service class with guice in dropwizard.
Consider the object
public class MinioData {
private String endpoint;
public String getEndpoint() {
return endpoint;
}
}
And a service
#Path("/upload")
#Produces(MediaType.APPLICATION_JSON)
public class UploadResource {
private final MinioData minioData;
#Inject
public UploadResource(
#Named("miniodata") MinioData minioData) {
this.minioData = minioData;
}
How can I bind this object so that can be used in my service. For a String I could use
bindConstant()
.annotatedWith(Names.named("miniodata"))
.to(configuration.getMiniodata());
but since in this case it is a general object how would I bind it?

If you have an existing Guice module configured in your DW application, you can just bind the MinioData instance from the configuration object to the associated class:
binder.bind(MinioData.class).toInstance(configuration.getMiniodata());

Related

Spring Boot - Web Application Context Bean Scope

I have a class A as a bean.
public class A
{
// constructors
// properties
// getters and setters
}
Spring boot configuration:
#Configuration
public class AConfig{
#Bean
#Scope(scopeName = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public A getA() {
return new A();
}
}
I am working right now with WebSocket and I am trying to get a new class A instance for some specific WebSocket channels, let's say if I am working with WebSocket id:1 then I will have the instance of A (some address) for that WebSocket, and for the WebSocket id:2 I will have another instance of A (some other address), and I can have it across application. How can I achieve that? In this case, I guess I have to send some ID to the server to identify the spring bean I am looking for.
**Instead of Autowired we should use Constructor arguments to make it loosely coupled **
class MessageSocketDemo {
private A a;
public MessageSocketDemo(A a) {
this.a = a;
}
public MessageSocketDemo() {
a = new A("address");
}
}
class A {
String address;
public A(String add) {
address = add;
}
}
So when you create object of MessageSocketDemo you create object of A every time new.
Or make the Scope of A as prototype or request which will create it new every time it is asked, and a lookup method to create instance of A

Best way to dynamically resolve dependencies in Java Spring?

Let's say I have this code structure:
public class NotificationService {
public void send(Notification notification) {
// call other services and send the notification
}
}
public class OrderNotification implements Notification {
#Autowired
public TranslationService translationService;
private String orderNumber;
public OrderNotification(String orderNumber) {
this.orderNumber = orderNumber;
}
public String getMessage() {
return translationService.trans('notification.order', new Object[]{orderNumber});
}
}
So, my goal is to use the NotificationService in this way:
notificationService.send(new OrderNotification(orderNumber));
But I know that code above won't work, because of the translationService won't be resolved.
My goal is to pass custom parameters to my Notification classes and being able to use services inside that class. What is the best way to do it in the Spring?
I know that below is not the correct answer to your question. It is however a bad design pattern to combine Entities and Services. An Entity should only contain information about the object and not business logic. A Service contains all the business logic.
You need to separate your Service from your Entity.
OrderNotification looks like a regular entity. The entity should not contain business logic. You need a specific service for the business logic.
public class OrderNotification implements Notification {
private String orderNumber;
public OrderNotification(String orderNumber) {
this.orderNumber = orderNumber;
}
public String getMessage() {
return "Order number: " + orderNumber;
}
//Getter & Setters
...
}
#Service
public class NotificationService {
#Autowired
public TranslationService translationService;
public void send(Notification notification) {
//I do not know what trans accepts, so I assume it can accept Notification
translationService.trans(notification.getMessage());
}
}
If you really need to combine the entity and service - Then I recommend this approach:
#Service
public class Master{
#Autowired
NotificationService notificationService
public void testMethod(){
Notification notification = notificationService.createOrder("order1");
notificationService.send(notification);
}
}
#Service
public class NotificationService {
#Autowired
public TranslationService translationService;
public Notification createOrder(String orderNumber){
return new OrderNotification(orderNumber, translationService);
}
public void send(Notification notification) {
// call other services and send the notification
notification.getMessage();
}
}
public class OrderNotification implements Notification {
private TranslationService translationService;
private String orderNumber;
//I have changed this constructor to accept TranslationService.
public OrderNotification(String orderNumber, TranslationService translationService) {
this.orderNumber = orderNumber;
this.translationService = translationService;
}
public String getMessage() {
return translationService.trans('notification.order', new Object[]{orderNumber});
}
}
You have few options available:
Configure AOP and load time weaving to process Spring annotations on objects created with new keyword. This is explained in the docs 5.8.1. Using AspectJ to dependency inject domain objects with Spring.
Declare OrderNotification as a prototype scoped bean and obtain each instance from the context using BeanFactory.getBean(Class<T> requiredType, Object... args) method.
String orderNumber = "123";
OrderNotificaton = factory.getBean(OrderNotificaton.class, orderNumber);
Drop the #Autowired and use plain constructor injection.
public OrderNotification(TranslationService translationService, String orderNumber) {
this.translationService = Objects.requireNonNull(translationService);
this.orderNumber = Objects.requireNonNull(orderNumber);
}
If you only require simple #Autowired I'd go with option 3. It's the simplest approach and makes writing unit tests easier as you don't have to depend on Spring.

Jersey: Detect when Controller Class is Created

I've implemented a JAX-RS server application using Jersey 2.24.
I use the Guice-HK2 bridge so that the controller classes (those annotated with #Path) are injected with dependencies from Guice, not Jersey/HK2.
However, HK2 still creates instances of the #Path annotated classes itself.
Is there a way I can plug into Jersey/HK2 so that I'm notified when a #Path annotated class is created? Like some sort of lifecycle listener? Every time a #Path annotated class is created by Jersey/HK2 I want to do some registering/logging of that class.
If Guice were doing the actual creation of the #Path annotated class I think I could do it using a generic Provider but that's not available in this case, since Jersey/HK2 is creating the actual instance.
Thank you!!
I think the least intrusive way would be to just use AOP. HK2 offers AOP. What you can do is create a ConstructorInterceptor. Something like
public class LoggingConstructorInterceptor implements ConstructorInterceptor {
private static final Logger LOG
= Logger.getLogger(LoggingConstructorInterceptor.class.getName());
#Override
public Object construct(ConstructorInvocation invocation) throws Throwable {
Constructor ctor = invocation.getConstructor();
LOG.log(Level.INFO, "Creating: {0}", ctor.getDeclaringClass().getName());
// returned instance from constructor invocation.
Object instance = invocation.proceed();
LOG.log(Level.INFO, "Created Instance: {0}", instance.toString());
return instance;
}
}
Then create a InterceptorService to only use the interceptor for classes annotated with #Path
public class PathInterceptionService implements InterceptionService {
private static final ConstructorInterceptor CTOR_INTERCEPTOR
= new LoggingConstructorInterceptor();
private final static List<ConstructorInterceptor> CTOR_LIST
= Collections.singletonList(CTOR_INTERCEPTOR);
#Override
public Filter getDescriptorFilter() {
return BuilderHelper.allFilter();
}
#Override
public List<MethodInterceptor> getMethodInterceptors(Method method) {
return null;
}
#Override
public List<ConstructorInterceptor> getConstructorInterceptors(Constructor<?> ctor) {
if (ctor.getDeclaringClass().isAnnotationPresent(Path.class)) {
return CTOR_LIST;
}
return null;
}
}
Then just register the InterceptionService and ConstructorInterceptor with the DI system
new ResourceConfig()
.register(new AbstractBinder(){
#Override
public void configure() {
bind(PathInterceptionService.class)
.to(InterceptionService.class)
.in(Singleton.class);
bind(LoggingConstructorInterceptor.class)
.to(ConstructorInterceptor.class)
.in(Singleton.class);
}
});
See complete example in this Gist
See Also:
HK2 documentation on AOP

Accessing main class from Jersey listener without the main class being a singleton object

I often use Jersey simple server as a webservice in my Java applications. Whenever I do this I only seem to be able to fetch properties from my application (main class) if it is setup as a singleton. So, I only seem to be able to fetch the information with MainClass.getInstance().
I know I can make the Jersey listener some sort of singleton in Jersey but this only means that the listener object will be instantiated once within Jersey in stead of for every single request: The listener is not a real singleton because it still needs a public constructor.
Is there a way to access my application class without it being a singleton object itself?
Here is the relevant code:
public class JerseyService {
private MainClass mainClass;
private int port = 8080;
private DefaultResourceConfig config;
private Closeable jerseyServer;
public JerseyService() {
config = new DefaultResourceConfig(JerseyListener.class); // Attach the listener (resource) to the Jersey server
jerseyServer = SimpleServerFactory.create("http://0.0.0.0:" + jerseyPort, config);
}
public String getData() {
return "somedata";
}
}
#Path("/")
public class JerseyListener {
#Path("getData")
#GET
#Produces("application/json")
public Response getData() {
// How can i call getData() from JerseyService
// without JerseyService being a singleton??
return Response.status(Response.Status.OK).entity("{<jsondata>}").build();
}
}

Perform service multiplexing with Apache Thrift and TServlet

I have a system (Java with Spring Framework) that exposes 7 different Apache Thrift servlets over HTTP using the TServlet class. Currently they all need their own Servlets, ServletMappings, Processors, Handlers etc. so implementing clients have to also keep an internal list of all the various URLs for the different services.
I understand that Apache Thrift supports multiplexing when using TServer and its derivatives by using TMultiplexingProcessor, however since I am using Spring and my Servlet, Handler and Processor are all Spring Beans that get autowired into one another, I'm unsure how to proceed.
Here's an example of how one of the services gets wired up:
UserServiceHandler.java
#Component
public class UserServiceHandler implements UserService.Iface {
#Override
public User getUser(String userId) throws TException {
// implementation logic goes here
}
}
UserServiceProcessor.java
#Component
public class UserServiceProcessor extends UserService.Processor<UserServiceHandler> {
private UserServiceHandler handler;
#Autowired
public UserServiceProcessor(UserServiceHandler iface) {
super(iface);
handler = iface;
}
public UserServiceHandler getHandler() {
return handler;
}
public void setHandler(UserServiceHandler handler) {
this.handler = handler;
}
}
UserServiceServlet.java
#Component
public class UserServiceServlet extends TServlet {
private UserServiceProcessor processor;
#Autowired
public UserServiceServlet(UserServiceProcessor p) {
super(p, new TBinaryProtocol.Factory());
processor = p;
}
}
Servlet Registration
ServletRegistration.Dynamic userService = servletContext.addServlet("UserServiceServlet", (UserServiceServlet) ctx.getBean("userServiceServlet"));
userService.setLoadOnStartup(1);
userService.addMapping("/api/UserService/*");
// This same block repeated 7 times for each *ServiceServlet with different mappings
I would like to have all 7 service handlers map to a single URL like /api/*. Is this even possible? I suppose I would have to create a single servlet and processor, but I'm unsure what they should look like. My processors extend UserService.Processor and the like.
OK, figured it out. Might not be the best way, so I welcome criticism.
Here were my rough steps:
Keep the handler classes the way they were.
Create a new class that extends TMultiplexedProcessor
Create a new class that extends TServlet
All Processors (e.g. the UserServiceProcessor have a handler property and a corresponding getter and setter
Here is my ApiMultiplexingProcessor:
#Component
public class ApiMultiplexingProcessor extends TMultiplexedProcessor {
UserServiceHandler userServiceHandler;
ReportServiceHandler reportServiceHandler;
// ... more service handlers can go here
#Autowired
public ApiMultiplexingProcessor(UserServiceProcessor userServiceProcessor, ReportServiceProcessor reportServiceProcessor) {
this.registerProcessor("UserService", userServiceProcessor);
this.registerProcessor("ReportService", reportServiceProcessor);
// add more registerProcessor lines here for additional services
userServiceHandler = userServiceProcessor.getHandler();
reportServiceHandler = reportServiceProcessor.getHandler();
// set any additional service handlers here
}
// getters and setters for the handlers
public UserServiceHandler getUserServiceHandler() {
return userServiceHandler;
}
public void setUserServiceHandler(UserServiceHandler userServiceHandler) {
this.userServiceHandler = userServiceHandler;
}
public ReportServiceHandler getReportServiceHandler() {
return reportServiceHandler;
}
public void setReportServiceHandler(ReportServiceHandler reportServiceHandler) {
this.reportServiceHandler = reportServiceHandler;
}
}
So to explain the above a bit, if you add any additional services, you need to add the *ServiceHandler classes as fields on this class, and create the getters and setters etc.
So now that we have that, we can create a new single servlet that will be added to the servlet context.
Here is my ApiServlet:
#Component
public class ApiServlet extends TServlet {
private ApiMultiplexingProcessor processor;
#Autowired
public ApiServlet(ApiMultiplexingProcessor p) {
super(p, new TBinaryProtocol.Factory());
processor = p;
}
}
And then you just add this servlet to the servlet context (from a bean) as before:
ServletRegistration.Dynamic api = servletContext.addServlet("ApiServlet", (ApiServlet) ctx.getBean("apiServlet"));
api.setLoadOnStartup(1);
api.addMapping("/api/*");
// yay now we have a single URL and a single servlet
This all could be helpful to someone else in my situation, so enjoy!
P.S. make sure when adapting your clients you use the TMultiplexedProtocol so that you can pass the service name through when talking to the server e.g.
TTransport transport = new THttpClient(new Uri("https://myapp.com/api/"));
TProtocol protocol = new TBinaryProtocol(transport);
TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "UserService");
UserService.Client userServiceClient = new UserService.Client(mp);

Categories