Java: pass parameter in constructor or method? - java

Currently I have a class, TransactionData, which is just a little bit more than a POJO. I build the object from an HTTPServletRequest. What I do:
public class TransactionData
{
// ...
public TransactionData(HttpServletRequest request) throws IOException
{
// do actual work here
}
}
There many WTF here, the most disturbing one is that the object TransactionData is tightly coupled to HTTPServletRequest. What I thought: create an interface, TransactionDataExtractor, with an extract() method, so that I might implement different classes to build the object.
public interface TransactionDataExtractor
{
public TransactionData extract();
}
But how do I pass the stuff needed to build the TransactionData to every implementation? The firt thing that came to mind was to use the different constructors, like this:
public class TransactionDataExtractorRequest implements TransactionDataExtractor
{
private HttpServletRequest httpRequest;
public TransactionDataExtractorRequest(HttpServletRequest httpRequest)
{
this.httpRequest = httpRequest;
}
public TransactionData extract()
{
// do whatever is required
}
}
But in this case whenever I need to build a new TransactionData object I have to create a new TransactionDataExtractorRequest. An implicit dependency I don't like at all.
The other alternative I could think of was passing an Object parameter to extract() and cast it whenever required, giving up the type safety and introducing a lot of boiler plate ugly code
public TransactionData extract(Object o)
{
HttpServletRequest h;
if (o instanceof HttpServletRequest)
{
h = (HttpServletRequest)o;
}
//...
}
I don't know if I have made myself clear. I do feel like I'm missing something, I know the solution is very simple but I can't get hold of it.
Any thoughts?
TIA.
EDIT: the problem might even be that my hunch is completely wrong and I may dismiss it without any regret

If your only problem is ensuring type safety when passing the source object to extract(), you can use generics:
public interface TransactionDataExtractor<E> {
public TransactionData extract(E source);
}
public class TransactionDataExtractorRequest
implements TransactionDataExtractor<HttpServletRequest> {
public TransactionData extract(HttpServletRequest source) { ... }
}

I do feel like I'm missing something ... Any thoughts?
Well my thought is that you are attempting to solve a problem that isn't really a problem. There's no obvious (to me) reason why the coupling you are trying to get rid of is actually harmful. Certainly, your attempts to remove the coupling are not making the code any easier to understand.

In case you rely on request parameters only, you can get request.getParameterMap() and use the Map instead. (if you need headers - getHeaders())

Creating/reusing a TransactionDataExtractorRequest instance isn't a problem, IMHO. You'd need to somewhere distinguish between the parameter types anyway and if you decouple TransactionData and the parameter types by using some sort of factory, what's wrong with that?

I'm still not convinced that much is gained by removing the dependency on HttpServletRequest, but I would suggest something along the lines of:
public class TransactionData {
public TransactionData(TransactionDataOptions options) throws IOException {
// do actual work here
}
}
//TransactionData wants some state that it currently gets from a HttpServletRequest,
//figure out what that state is, and abstract an interface for accessing it
public interface TransactionDataOptions {
//getters for things that TransactionData needs
}
//take all the code that pulls state out of the HttpServletRequest, and move it here
public class TransactionDataHttpOptions implements TransactionDataOptions {
private HttpServletRequest request;
//getter implementations that pull the required information out of the request
public TransactionDataHttpOptions(HttpServletRequest request) {
this.request = request;
}
}
//now you can also do this, and use TransactionData even without a HttpServletRequest
public class TransactionDataMapOptions implements TransactionDataOptions {
private Map<String, Object> map;
//getter implementations that pull the required information out of the map
public TransactionDataHttpOptions(Map<String, Object> map) {
this.map = map;
}
}
If you go this route, then TransactionDataHttpOptions is the only object with a dependency on HttpServletRequest. And since it is basically a wrapper that is intended to work with a HttpServletRequest I think that should be fine.

Related

Dynamic dependency injection for multiple implementations of the same interface with Spring MVC

I am working on a REST API where I have an interface that defines a list of methods which are implemented by 4 different classes, with the possibility of adding many more in the future.
When I receive an HTTP request from the client there is some information included in the URL which will determine which implementation needs to be used.
Within my controller, I would like to have the end-point method contain a switch statement that checks the URL path variable and then uses the appropriate implementation.
I know that I can define and inject the concrete implementations into the controller and then insert which one I would like to use in each particular case in the switch statement, but this doesn't seem very elegant or scalable for 2 reasons:
I now have to instantiate all of the services, even though I only need to use one.
The code seems like it could be much leaner since I am literally calling the same method that is defined in the interface with the same parameters and while in the example it is not really an issue, but in the case that the list of implementations grows ... so does the number of cases and redundant code.
Is there a better solution to solve this type of situation? I am using SpringBoot 2 and JDK 10, ideally, I'd like to implement the most modern solution.
My Current Approach
#RequestMapping(Requests.MY_BASE_API_URL)
public class MyController {
//== FIELDS ==
private final ConcreteServiceImpl1 concreteService1;
private final ConcreteServiceImpl2 concreteService2;
private final ConcreteServiceImpl3 concreteService3;
//== CONSTRUCTORS ==
#Autowired
public MyController(ConcreteServiceImpl1 concreteService1, ConcreteServiceImpl2 concreteService2,
ConcreteServiceImpl3 concreteService3){
this.concreteService1 = concreteService1;
this.concreteService2 = concreteService2;
this.concreteService3 = concreteService3;
}
//== REQUEST MAPPINGS ==
#GetMapping(Requests.SPECIFIC_REQUEST)
public ResponseEntity<?> handleSpecificRequest(#PathVariable String source,
#RequestParam String start,
#RequestParam String end){
source = source.toLowerCase();
if(MyConstants.SOURCES.contains(source)){
switch(source){
case("value1"):
concreteService1.doSomething(start, end);
break;
case("value2"):
concreteService2.doSomething(start, end);
break;
case("value3"):
concreteService3.doSomething(start, end);
break;
}
}else{
//An invalid source path variable was recieved
}
//Return something after additional processing
return null;
}
}
In Spring you can get all implementations of an interface (say T) by injecting a List<T> or a Map<String, T> field. In the second case the names of the beans will become the keys of the map. You could consider this if there are a lot of possible implementations or if they change often. Thanks to it you could add or remove an implementation without changing the controller.
Both injecting a List or a Map have some benefits and drawbacks in this case. If you inject a List you would probably need to add some method to map the name and the implementation. Something like :
interface MyInterface() {
(...)
String name()
}
This way you could transform it to a Map<String, MyInterface>, for example using Streams API. While this would be more explicit, it would polute your interface a bit (why should it be aware that there are multiple implementations?).
When using the Map you should probably name the beans explicitly or even introduce an annotation to follow the principle of least astonishment. If you are naming the beans by using the class name or the method name of the configuration class you could break the app by renaming those (and in effect changing the url), which is usually a safe operation to do.
A simplistic implementation in Spring Boot could look like this:
#SpringBootApplication
public class DynamicDependencyInjectionForMultipleImplementationsApplication {
public static void main(String[] args) {
SpringApplication.run(DynamicDependencyInjectionForMultipleImplementationsApplication.class, args);
}
interface MyInterface {
Object getStuff();
}
class Implementation1 implements MyInterface {
#Override public Object getStuff() {
return "foo";
}
}
class Implementation2 implements MyInterface {
#Override public Object getStuff() {
return "bar";
}
}
#Configuration
class Config {
#Bean("getFoo")
Implementation1 implementation1() {
return new Implementation1();
}
#Bean("getBar")
Implementation2 implementation2() {
return new Implementation2();
}
}
#RestController
class Controller {
private final Map<String, MyInterface> implementations;
Controller(Map<String, MyInterface> implementations) {
this.implementations = implementations;
}
#GetMapping("/run/{beanName}")
Object runSelectedImplementation(#PathVariable String beanName) {
return Optional.ofNullable(implementations.get(beanName))
.orElseThrow(UnknownImplementation::new)
.getStuff();
}
#ResponseStatus(BAD_REQUEST)
class UnknownImplementation extends RuntimeException {
}
}
}
It passes the following tests:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class DynamicDependencyInjectionForMultipleImplementationsApplicationTests {
#Autowired
private MockMvc mockMvc;
#Test
public void shouldCallImplementation1() throws Exception {
mockMvc.perform(get("/run/getFoo"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("foo")));
}
#Test
public void shouldCallImplementation2() throws Exception {
mockMvc.perform(get("/run/getBar"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("bar")));
}
#Test
public void shouldRejectUnknownImplementations() throws Exception {
mockMvc.perform(get("/run/getSomethingElse"))
.andExpect(status().isBadRequest());
}
}
Regarding two of your doubts :
1. Instantiating the service object should not be an issue as this is one time job and controller gonna need them to serve all type of request.
2. You can use the exact Path mapping to get rid of switch case. For e.g. :
#GetMapping("/specificRequest/value1")
#GetMapping("/specificRequest/value2")
#GetMapping("/specificRequest/value3")
All of the above mapping will be on separate method which would deal with specific source value and invoke respective service method.
Hope this will help to make code more cleaner and elegant.
There is one more option of separating this on service layer and having only one endpoint to serve all types of source but as you said there is different implementation for each source value then it says that source is nothing but a resource for your application and having separate URI/separate method makes the perfect sense here. Few advantages that I see here with this are :
Makes it easy to write the test cases.
Scaling the same without impacting any other source/service.
Your code dealing the each source as separate entity from other sources.
The above approach should be fine when you have limited source values. If you have no control over source value then we need further redesign here by making source value differentiate by one more value like sourceType etc. and then having separate controller for each group type of source.

Where is the right place for annotation processing?

I write simple application. I don't want to use any frameworks. Please suggest me right place to hold annotation processing.
I have a few lines in main method:
String myString = (#NonNull String)list;
And I created #interface:
#Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
public #interface NonNull {
}
Which step should I take next? Can I work with annotations without using reflection? Could you expose for me samples of such annotation processing code?
There is no way (AFAIK) to work with annotations without reflection.
If you don't want to use any framework, first step is to write kind of proxy class handling the method requests. It is an example of method processing with annotation use over method:
public class MyProxy {
private <T> T getProxy(T t) {
return (T) Proxy.newProxyInstance(t.getClass().getClassLoader(), new Class<?>[]{MyClass.class}, new MyInvocationHandler(t));
}
}
And then implement InvocationHandler:
public class MyInvocationHandler implements InvocationHandler {
private Object obj;
MyInvocationHandler (Object obj) {
this.obj = obj;
}
#Override
public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
boolean isNotNull = method.isAnnotationPresent(NotNull.class);
if (isNotNull) {
/* process annotated method. Or go through proxy object fields etc.. */
}
}
}
I hope it will help you.
You didn't say what kind of annotation processing you want to do.
Do you want to add a run-time check that will cause your code to crash if list is ever null at run time? For this, reflection will work.
Do you want to add a compile-time check that will reject your code if it cannot prove that list is never null at run time? For this, an annotation processor such as the Checker Framework will work.
Your question does not explain why you don't want to use a framework. Doing so will save you from re-implementing a lot of functionality that others have already created.

Factory and generics

I have the following classes:
public interface IDataSource<T> {
public List<T> getData(int numberOfEntries);
}
public class MyDataSource implements IDataSource<MyData> {
public List<MyData> getData(int numberOfEntries) {
...
}
}
public class MyOtherDataSource implements IDataSource<MyOtherData> {
public List<MyOtherData> getData(int numberOfEntries) {
...
}
}
I would like to use a factory that return the correct implementation based on the data type. I wrote the following but I get "Unchecked cast" warnings:
public static <T> IDataSource<T> getDataSource(Class<T> dataType) {
if (dataType.equals(MyData.class)) {
return (IDataSource<T>) new MyDataSource();
} else if (dataType.equals(MyOtherData.class)) {
return (IDataSource<T>) new MyOtherDataSource();
}
return null;
}
Am I doing it wrong? What can I do to get rid of the warnings?
I am not aware of any way to get rid of those warnings without #SuppressWarnings("unchecked").
You are passing in a Class object so T can be captured. But you are forced to check the Class at runtime to determine which IDataSource<T> to return. At this time, type erasure has long since occurred.
At compile time, Java can't be sure of type safety. It can't guarantee that the T in the Class at runtime would be the same T in the IDataSource<T> returned, so it produces the warning.
This looks like one of those times when you're forced to annotate the method with #SuppressWarnings("unchecked") to remove the warning. That warning is there for a reason, so it is up to you to provide and ensure type safety. As written, it looks like you have provided type safety.
#SuppressWarnings("unchecked")
public static <T> IDataSource<T> getDataSource(Class<T> dataType) {
You're doing it right, and you should simply suppress the warnings. Factories are one of the tricky areas in generics where you really do need to manually cast to a generic type, and you have to ensure via whatever means that the returned value matches the Class<T> you pass in. For example, in this case you're hard-coding a couple of IDataSource implementations, so I would recommend writing unit tests that verify that the types are correct so that if the MyData implementation changes in an incompatible way, you'll get an error on build.
Just annotate the getDataSource method with #SuppressWarnings("unchecked"), and it's always a good idea to add an explanatory comment when suppressing warnings.
Generics are for compile-time type safety. They can't be used for runtime type determination like that. To get rid of the warning, you can do something like #SuppressWarnings("unchecked") or use the -Xlint:-unchecked compiler flag, as described in the "Raw Types" part of the Java tutorial.
The other answers have answered the problem as you posed it. But I'd like to take a step back to understand what you're trying to accomplish with this factory method. This factory basically provides a map of data types to IDataSource parameters. Dependency injection might be a more appropriate pattern since this is a small well-known set of data types and implementations (as indicated by your example).
Let's say you want to store all Widgets in Mongo but all Gadgets in Mysql, you might have two classes: a MongoWidgetDataSource that implements IDataSource<Widget> and a MysqlGadgetDataSource that implements IDataSource<Gadget>.
Instead of hardcoding a factory method call like MyFactory.getDataSource(Widget.class) inside a data consumer, I would inject the appropriate IDataSource dependency. We might have MyService that does something with widgets (stored in mongo). Using a factory as you proposed would look like this:
public class MyService {
public void doSomething() {
String value = MyFactory.getDataSource(Widget.class).getSomething();
// do something with data returned from the source
}
}
Instead, you should inject the appropriate data source as a constructor arg into the service:
public class MyService {
private final IDataSource<Widget> widgetDataSource;
public MyService(IDataSource<Widget> widgetDataSource) {
this.widgetDataSource = widgetDataSource;
}
public void doSomething() {
String value = widgetDataSource.getSomething();
// now do something with data returned from the source
}
}
This has the added benefit of making your code more reusable and easier to unit test (mock dependencies).
Then, where you instantiate MyService, you can also wire up your data sources. Many projects use a dependency injection framework (like Guice) to make this easier, but its not a strict requirement. Personally, though, I never work on a project of any real size or duration without one.
If you don't use an DI framework, you just instantiate the dependencies when you create the calling service:
public static void main(String[] args) {
IDataSource<Widget> widgetDataSource = new MongoWidgetDataSource();
IDataSource<Gadget> gadgetDataSource = new MysqlGadgetDataSource();
MyService service = new MyService(widgetDataSource, gadgetDataSource);
service.doSomething();
}
In Guice, you would wire up these data sources like this:
public class DataSourceModule extends AbstractModule {
#Override
protected void configure() {
bind(new TypeLiteral<IDataSource<Widget>>() {}).to(MongoWidgetDataSource.class);
bind(new TypeLiteral<IDataSource<Gadget>>() {}).to(MysqlGadgetDataSource.class);
}
}
Dependency inversion is a bit of a different way to think about the problem, but it can lead to a much more decoupled, reusable and testable code base.
This seems to work:
public static <T> IDataSource<T> getDataSource(MyData dataType) {
System.out.println("Make MyDataSource");
return (IDataSource<T>) new MyDataSource();
}
public static <T> IDataSource<T> getDataSource(MyOtherData dataType) {
System.out.println("Make MyOtherDataSource");
return (IDataSource<T>) new MyOtherDataSource();
}
public void test() {
IDataSource<MyData> myDataSource = getDataSource((MyData) null);
IDataSource<MyOtherData> myOtherDataSource = getDataSource((MyOtherData) null);
}
You may prefer to create empty archetypes rather than cast null like I have but I think this is a viable technique.

How to set the values to one setter method using Reflection without knowing class?

I am new to java reflection.I will directly come to the question.
This is my class
public class RequestClass{
#XmlElement(name="Request")
private Request mRequest;
public Request getRequest() {
return mRequest;
}
public void setRequest(Request request) {
this.mRequest= request;
}
this my another class in this I am passing RequestClass object here
//The supplied requestObject is of type RequestClass
Object initialize(Object requestObject) {
//requestObject
}
In this code I want to manipulate, dynamically, the request property of the RequestClass. I don't know how to proceed further, so if anyone could provide some guidance, I would appreciate it. Thanks.
try this requestObject.getClass().getMethod(method_name).invoke(requestObject);
also, there is an overload of getMethod & invoke, through which you can pass parameter to that method (like in setters)

Get all beans implementing a generic interface in Spring

How do I get a reference of all beans implementing a specific generic interface (e.g. Filter<TestEvent>) in Spring?
This is what I want to achieve with a minimum number of lines:
public interface Filter<T extends Event> {
boolean approve(T event);
}
public class TestEventFilter implements Filter<TestEvent> {
public boolean approve(TestEvent event){
return false;
}
}
public class EventHandler{
private ApplicationContext context;
public void Eventhandler(DomainEvent event) {
// I want to do something like following, but this is not valid code
Map<String, Filter> filters = context.getBeansOfType(Filter<event.getClass()>.class);
for(Filter filter: filters.values()){
if (!filter.approve(event)) {
return; // abort if a filter does not approve the event
}
}
//...
}
}
My current implementation uses reflection to determine if filter.approve does accept the event before calling it.
E.g.
Map<String, Filter> filters = context.getBeansOfType(Filter.class);
for(Filter filter: filters.values()){
if (doesFilterAcceptEventAsArgument(filter, event)) {
if (!filter.approve(event)) {
return; // abort if a filter does not approve the event
}
}
}
Where the doesFilterAcceptEventAsArgument does all the ugly work that I would like would like to get away from. Any suggestions?
Just for reference, the simplest solution I could construct was this:
Map<String, Filter> filters = context.getBeansOfType(Filter.class);
for(Filter filter: filters.values()){
try {
if (!filter.approve(event)) {
return; // abort if a filter does not approve the event.
}
} catch (ClassCastException ignored){ }
}
And it worked quite well for prototyping.
If your question is "does Spring have a nicer way to do this", then the answer is "no". Hence, your method looks like the ubiquitous way to achieve this (get all beans of the raw class, then use reflection to look up the generic bound and compare it with the target's class).
In general, using generic information at runtime is tricky if possible at all. In this case you can get the generic bounds, but you're not really getting much benefit from the generic definition itself, other than using it as a form of annotation to check manually.
In any case, you will have to perform some kind of check on the returned object, so your original code block isn't going to work; the only variation is in the implementation of doesFilterAcceptEventAsArgument. The classic OO way, would be to add an abstract superclass with two methods as follows (and add the latter to the Filter interface):
protected abstract Class<E> getEventClass();
public boolean acceptsEvent(Object event) // or an appropriate class for event
{
return getEventClass().isAssignableFrom(event.getClass());
}
This is kind of a pain because you'll have to implement the trivial getEventClass() methods in every implementation to return the appropriate class literal, but it's a known limitation of generics. Within the bounds of the language, this is likely the cleanest approach.
But yours is fine for what it's worth.

Categories

Resources