Can I use injected beans as arguments for another class' method? - java

I am working on a hibernate project and I'm moving some logic from a BLL class to a DTO, and I was wondering if it's possible to inject objects into a DTO? The code from the BLL class relied on a lot of imported beans, but when I tried importing them into my DTO object my applicationContext would mess up.
FlightHelper class:
public class FlightHelper {
#Inject
private InjectedClass injectedClass;
public void testMethod(Flight flight) {
...code here
flight.getPrice(injectedClass);
}
}
Flight class:
public class Flight {
public void getPrice(InjectedClass injectedClass) {
...code here
}
}

Yes, you can.
However, the design is not very nice because you have a very strong interaction between Flight and FlightHelper classes.

yes you can, but you might want to instead inject them in the other class aswell.

Related

Unable to call function of autowired class

I have the following classes :
Class 1:
package com.assets;
#Component
#Scope("request)
public class AssetDetailsImpl implements AssetApi
{
public void function1(){
....
}
public void function2(){
AssetUtil.test1();
}
}
Class 2:
package com.assets;
#Component
public class AssetUtil
{
#Autowired
AssetDetailsImpl impl;
//some functions
public static void test1{
impl.function1();// NPE I am getting
}
Here my auto wiring not working, its coming null. Both the classes are in the same package. Is it because of the request scope which is there in AssetDetailsImpl? I even tried with #Inject that also was not working. Can anyone please help me to resolve this? Thanks in advance!
I have tried removing the scope, but then also the same problem.
I have also tried:
AssetUtil(AssetDetailsImpl impl) {
this.impl = impl;
}
But I am not sure how to deal with the static thing then also how to invoke this constructor?
The method test1 is static.
But Spring doesn't work with static members because it creates instances of the beans.
Remove static:
public void test1{
impl.function1();
}
And now you have to make sure that the client of this method is also using autowiring to get an instance of AssetUtil
It looks to me like the issue is that the AssetDetailsImpl Component is Request-scoped, which means it comes and goes with each HTTP request, while the AssetUtil Component which is trying to use it is default-scoped, which is Application/singleton scope.
Personally, I try to use singletons as much as possible. I wouldn't use request scope for the first Component.

Is it safe to use String as a return type of a bean in spring?

#Configuration
public class Product {
#Bean("xyz")
public String getMethod() {
return "abc";
}
}
#Component
public class Test {
String b;
Test(String xyz) {
this.b = xyz;
}
}
Is this any harm with this approach? I am trying to make change in the existing code where I am replacing the #Value with the getter as the method parameter. As I don't want to change the structure of the existing code I am trying to inject the method as bean as a replacement to #Value.
I suggest you to keep the #Value annotation instead of the whole #Bean configurations.
Why?
What if the getMethod()'s returned value needs to be changed very often? Everytime when you're changing something in the Product class, during build time it needs to be recompiled. What happens if the project is getting bigger and you're using this approach? It leads to longer build time and the more important thing is that this solution is not intuitive and it's hard to keep it clean. Don't think about complex solutions only to make the code look fancy. When you need to inject String values, the easiest approach is to create properties files (which won't get recompiled) and use the #Value annotation.
Now, if you want to add new methods without changing the structure of the existing code there are some patterns which you can apply like decorator pattern.
The main idea is simple: you're creating a decorator class which has an object of the type you need.
The easiest example (which you'll find everywhere on the internet) is the classic Shape example:
public interface Shape {
String someMethod();
}
#Component
public class CustomShape implements Shape { //implement the method here }
And here is the decorator:
public interface ShapeDecorator {
String someMethodExtended();
void someExtraMethod();
}
#Component
public class CustomShapeDecorator implements ShapeDecorator{
#Autowired
// #Qualifier - optional (only if you have more Shape implementations)
private Shape shape;
// now you can either:
// 1. provide new methods
#Override
public void someExtraMethod(){
System.out.println("Hello world!");
}
// 2. or you can EXTEND the Shape's "someMethod()" implementation
#Override
public String someMethodExtended(){
String oldString = this.shape.someMethod();
return oldString + " EXTENDED";
}
}

#Service, #Repository class dependency-injection to static field is good for static method usage?

Using static-method makes code more clean.
So I wanna use static-method even used with #Service, #Repository class in it.
You can more easily understand by code. Very short one and It works!!
But I want to know it is okay to use in any situation.
I didn't see like that code before, so I am afraid it is the effective code to use. If you have any idea about that, could you advise me, please?
#Repository
public class TruckRepository {
public Integer selectWheelCount() {
//which is searching truck database to get some data about trucks.
//Such as how many wheels does the truck have, something like that.
}
}
#Component
public class CarFactory {
private static TruckRepository truckRepository;
//#Autowired << can be omitted after spring 4.3 as I know
NewsSourceFactory(TruckRepository truckRepository) {
this.truckRepository = truckRepository;
}
public static Integer getWheelCount(String carType) {
swtich(carType) {
case TRUCK:
return truckRepository.selectWheelCount();
}
}
}
#Component
public class SomeCode {
public void something() {
Integer count = CarFactory.getWheelCount("TRUCK");
}
}
Add Comments
I very empressive the code of "Duration.class", "Stream.class" in java.
They are also using static-method, Of course they have no dynamic injection in there.
Just in case of thinking about the concise of code or clearness, isn't it the merit of static-method, dont you think? is it really harmless?
You are using static method which uses static field which is initialized in constructor. In this code it's not even clear when Spring will create a new instance of CarFactory (maybe it won't at all, if none is referencing it). And if no instance of CarFactory created, your static method is broken too, because static field is not initialized.
I don't see any benefits of using static methods in your case, after all you can always inject instance of CarFactory into SomeCode.
Simple as:
#Autowired
private CarFactory cartFactory;
Or better:
private CarFactory cartFactory;
public SomeCode(#Autowired CarFactory pCartFactory) {
cartFactory = pCartFactory;
}

factory like pattern with spring bean without switch case

My goal is to return a method depending on a enum. Currently, I have created a factory but it's using a switch case that I dislike. The code is working fine but I want to use a better pattern and replace the current switch case. How would you design this without any switch case or if else (instance of)...
I tried also to implement a Stategy pattern in enum. But autowiring beans is not possible.
See below my current piece of code.
public enum Car {
AUDI, FORD;
}
public class SuperCar{
private Car car;
}
public class Audi extends SuperCar{
// some other properties
}
public class Ford extends SuperCar{
// some other properties
}
#Service
public class AudiService{
public void save(Audi audi){
// some code
}
}
#Service
public class FordService{
public void save(Ford ford){
// some code
}
}
#Service
public class CarFactory{
private FordService fordService;
private AudiService audiService;
public CarFactory(FordService fordService, AudiService audiService) {
this.fordService = fordService;
this.audiService = AudiService;
}
public void saveCar(SuperCar superCar){
switch(superCar.getCar()):
case AUDI:
return audiService.save((Audi)superCar));
case FORD:
return fordService.save((Ford)superCar));
default:
return null;
}
}
Thank you for any help.
In case of just replacing the switch, I would always prefer a more declarative approach by using a map, since it seams easier to maintain and to read:
private Map<Car, CarService> services;
public CarFactory(FordService fordService, AudiService audiService) {
this.services = Map.of(Car.FORD, fordService, Car.AUDI, audiService);
}
public void saveCar(SuperCar superCar) {
CarService service = services.get(superCar.getCar());
if (service != null) service.save(..);
}
With the generic interface:
private interface CarService<T extends SuperCar> {
void save(T car);
}
Anyway, I would rethink your object-model to let a super-car save itself (as others already suggested).
I'm sorry that I can't comment. Here the type of the car determines the car service. I'm not sure If the strategy patterns fits in here. I would use strategy pattern when there is a varying service behavior for the same car. Eg: In summer I want to use XService and in Winter I want to use YService for AUDI. I see two ways to implement this.
Inject the service during the creation of car object. With this implementation the car is tightly coupled with service. I don't recommend this, unless you have a strong reason to not follow point 2.
Use if/else or branching to determine the type of car and call the required service.

Dagger 2 on Android #Singleton annotated class not being injected

I am currently trying to integrate Dagger 2 into an Android application. My project setup is as follows:
library
app (depends on library)
In my library project I defined a class that I'll later inject into other classes that need it (Activities and regular classes) in the library as well as the app project.
#Singleton
public class MyManager{
#Inject
public MyManager(){
//Do some initializing
}
}
Now - for instance in my Fragments or Activities or regular classes I'd inject the above Singleton as follows:
public class SomeClass{
#Inject
MyManager myManager;
}
Or so I thought, because in practice myManager is always null. And apparently it's constructor is never called either, so I guess I must be missing something configuration-wise? Or maybe I misunderstood the documentation and it's not meant to work this way at all? The purpose of MyManager class is to be an application-wide accessible component-accumulating entity - that's why I went for the #Singleton.
UPDATE
To avoid confusion: I mentioned my having components somewhere in a comment I think - this refers to components in the sense of "component based design" and has nothing to do with dagger. The dagger-based code I have is all listed above - there is nothing else related to dagger in my code.
When I started adding #Component I had some compiler issues, because my dagger2 was not setup properly - check out this really helpful thread on how to setup dagger2 correctly: https://stackoverflow.com/a/29943394/1041533
UPDATE 2
Here is my updated code, based on G. Lombard's suggestions - I changed the code as follows - the original Singleton is in the library project:
#Singleton
public class MyManager{
#Inject
public MyManager(){
//Do some initializing
}
}
Also in the library project is the bootstrap class:
#Singleton
#Component
public interface Bootstrap {
void initialize(Activity activity);
}
Then I use the above Bootstrap class in my activity (in my concrete app, NOT in the library project! I do however also have Classes/Activities in the library that'll access Bootstrap to inject MyManager):
public class MyActivity extends Activity{
#Inject
MyManager manager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//DONT DO THIS !!! AS EXPLAINED BY EpicPandaForce
DaggerBootstrap.create().initialize(this);
}
}
But even after this line:
DaggerBootstrap.create().initialize(this);
the manager instance is still null, i.e. not injected.
I just found this: https://stackoverflow.com/a/29326023/1041533
Which if I don't misread, implies I need to specify every single class in the Bootstrap class that will use #Inject to have stuff injected. Sadly - this is not an option, as I have more than 40 classes and activities for which I'd have to do that.
Meaning my Bootstrap interface apparently would have to look something like this:
#Singleton
#Component
public interface Bootstrap {
void initialize(ActivityA activity);
void initialize(ActivityB activity);
void initialize(ActivityC activity);
void initialize(ActivityD activity);
void initialize(ActivityE activity);
void initialize(ActivityF activity);
//and so on and so forth...
}
If the above is true, that would not be worth it for my use case. Plus: Seems there is no compile-time check, if I forgot to specify one of my 40+ classes here? It just wont work - i.e. crash the app at runtime.
You're making a mistake in that you are using
DaggerBootstrap.create().initialize(this);
in your Activity, as scopes are not shared across multiple component instances. What I recommend is using a custom application class
public class CustomApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Bootstrap.INSTANCE.setup();
}
}
#Component
#Singleton
public interface _Bootstrap {
void initialize(ActivityA activityA);
//void initiali...
}
public enum Bootstrap {
INSTANCE;
private _Bootstrap bootstrap;
void setup() {
bootstrap = Dagger_Bootstrap.create();
}
public _Bootstrap getBootstrap() {
return bootstrap;
}
}
Then you could call it as
Bootstrap.INSTANCE.getBootstrap().initialize(this);
This way, you share the component across your classes. I personally named Bootstrap as injector, and _Bootstrap as ApplicationComponent, so it looks like this:
Injector.INSTANCE.getApplicationComponent().inject(this);
But that's just my typical setup. Names don't really matter.
EDIT: To your last question, you can solve this by subscoping and component dependencies.
Your library project should be able to see only the library classes, correct? In that case, all you do is
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface LibraryScope {
}
#Component(modules={LibraryModule.class})
#LibraryScope
public interface LibraryComponent {
LibraryClass libraryClass(); //provision method for `MyManager`
}
#Module
public class LibraryModule {
#LibraryScope
#Provides
public LibraryClass libraryClass() { //in your example, LibraryClass is `MyManager`
return new LibraryClass(); //this is instantiation of `MyManager`
}
}
public enum LibraryBootstrap {
INSTANCE;
private LibraryComponent libraryComponent;
static {
INSTANCE.libraryComponent = DaggerLibraryComponent.create();
}
public LibraryComponent getLibraryComponent() {
return libraryComponent;
}
}
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface ApplicationScope {
}
#Component(dependencies={LibraryComponent.class}, modules={AdditionalAppModule.class})
#ApplicationScope
public interface ApplicationComponent extends LibraryComponent {
AdditionalAppClass additionalAppClass();
void inject(InjectableAppClass1 injectableAppClass1);
void inject(InjectableAppClass2 injectableAppClass2);
void inject(InjectableAppClass3 injectableAppClass3);
}
#Module
public class AdditionalAppModule {
#ApplicationScope
#Provides
public AdditionalAppClass additionalAppClass() { //something your app shares as a dependency, and not the library
return new AdditionalAppClass();
}
}
public enum ApplicationBootstrap {
INSTANCE;
private ApplicationComponent applicationComponent;
void setup() {
this.applicationComponent = DaggerApplicationComponent.builder()
.libraryComponent(LibraryBootstrap.INSTANCE.getLibraryComponent())
.build();
}
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
}
Then
#Inject
LibraryClass libraryClass; //MyManager myManager;
...
ApplicationBootstrap.INSTANCE.getApplicationComponent().inject(this);
It's hard to say what your problem was, since you didn't show what your Component looks like and whether you have multiple components etc.
Assuming this logical structure:
/app
MainComponent
SomeClass // where MyManager is to be injected
MainActivity // where SomeClass is to be injected
/library
LibraryComponent
MyManager // Singleton
Then your classes as listed would inject correctly with the following configuration:
#Singleton
#Component
public interface LibraryComponent {
MyManager getMyManager();
}
and the app-level component to inject dependencies into the activity:
#ActivityScope
#Component(dependencies = LibraryComponent.class)
public interface MainComponent {
void inject(MainActivity mainActivity);
}
Note that MainComponent depends on LibraryComponent, but because the latter has singleton scope, you need to define a scope for the other one too, which I was I used the "activity scope" here. (Or you could also just make the MainComponent a singleton and get rid of the LibraryComponent completely if that suits your needs.)
Finally it's all injected into the activity like this:
#Inject
SomeClass someClass;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder()
.libraryComponent(DaggerLibraryComponent.create())
.build()
.inject(this);
someClass.doSomething();
}
I've put a working sample here on GitHub
Update 1:
If I understand your setup correctly, you've so far only used the #Singleton and #Inject annotations on the two classes listed (MyManager and SomeClass), and there is no other Dagger-related code in your project.
In that case, the reason your MyManager isn't getting injected, is because Dagger doesn't know how to provide/instantiate the dependencies. This is where the "components" come in that I mentioned above. Without any Dagger 2 components (interface or abstract class annotated with #Component), your dependencies won't get injected automatically.
I don't know if you have experience with Dependency Injection concepts, but assuming you don't, I'll step through the minimum basics you'll need to understand to get your MyManager injected into SomeClass:
First: when you use DI, you need to understand the difference between "newables" and "injectables". This blogpost by Misko Hevery explains the details.
This means, you can't new up your SomeClass. This won't work:
mSomeClass = new SomeClass();
Because if you did that (say in an activity or fragment), Dagger will have no idea that you expected a dependency to get injected into SomeClass and it has no opportunity to inject anything.
In order for its dependencies to get injected, you have to instantiate (or inject) SomeClass itself through Dagger too.
In other words, say in your Activity where SomeClass is used, you'll need:
#Inject
SomeClass mSomeClass;
Next, you need a Dagger component to perform the actual injection. To create a component, you create an interface with a method that takes your root object (say MainActivity) as argument, e.g.:
#Singleton
#Component
public interface Bootstrap {
void initialize(MainActivity activity);
}
Now when you build your project, Dagger 2 generates a class called DaggerBootstrap that implements this interface. You use this generated class to perform the injection, say in your activity's onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerBootstrap.create().initialize(this);
mSomeClass.doSomething();
}
I believe this generated component is the key part you're missing. Full code for above here.
Some useful Dagger 2 resources:
the official Dagger 2 guide
reddit page with lots of links
Update 2:
Seems like the final missing piece of the puzzle was that your component provided an inject method for the Activity base class, but not for your actual concrete activity.
Unfortunately Dagger 2 requires an inject method for each activity or other class you want to inject into.
As you mentioned, this will be annoying when you have many different activities in your app. There some possible workarounds for this, search for "dagger 2 inject base class", for example this suggestion by #EpicPandaForce: Dagger 2 base class injections
Also note, as pointed out by #EpicPandaForce in the comments, that in my simplistic example I called DaggerLibraryComponent.create() every time which is probably not what you want, since that component is supposed to provide your singletons, so you're probably better off getting the existing instance from somewhere else such as from your Application instance.

Categories

Resources