I have a class which has a constructor where all the arguments are injected by GUICE.
Public class Order {
private final ClassOne classOneObj;
private final ClassTwo classTwoObj;
#Inject
public order(ClassOne classOneObj, ClassTwo classTwoObj){
this.classOneObj = classOneObj;
this.classTwoObj = classTwoObj;
}
}
Now, I want to add one more field(say, int status)variable which can't be injected.
Is it a good practice to create an object first with all the injected parameters and then set the new field which can't be injected with a setter method?
I came up with another approach where I created a factory class as given below:
public class OrderFactory {
private final ClassOne classOneObj;
private final ClassTwo classTwoObj;
#Inject
public order(ClassOne classOneObj, ClassTwo classTwoObj){
this.classOneObj = classOneObj;
this.classTwoObj = classTwoObj;
}
//getter methods for all the above variables
public ClassOne getclassOneObj(){
return classOneObj;
}
....
public Order createOrder(int status) {
return new Order(status, classOneObj, classTwoObj);
}
}
Then the new Order class will look like
public class Order {
int status
private final ClassOne classOneObj;
private final ClassTwo classTwoObj;
public order(int status, ClassOne classOneObj, ClassTwo classTwoObj){
this.status = status
this.classOneObj = classOneObj;
this.classTwoObj = classTwoObj;
}
//getter methods for all these member variables
}
Now to create the order object I will first create an OrderFactory object and then using the "createOrder" method I will create the Order object.
I am ending up with writing boilerplate code. Not sure if this is a good practice. Can anybody suggest on this if this approach is correct or there is any better approach for this problem?
I read in Google Guice and found there is a feature #Assisted for assisted injection for such cases. But I found that complex and couldn't convince myself whether I should go with that in my case.
Thanks in advance for any suggestion or guidance.
Your factory approach is excellent. Please don't use the setters: if the field can be made immutable, it should be immutable, whether or not it makes it "convenient" to instantiate.
Another approach you can take is Assisted Injection, which solves this exact problem. With that, you only define the factory interface, and its implementation is magically given to you by Guice:
class Order {
interface Factory {
Order create(Status status);
}
#AssistedInject Order(
ClassOne one,
ClassTwo two,
#Assisted Status status) {
}
}
Module code:
bind(Order.Factory.class).toProvider(
FactoryProvider.newFactory(Order.Factory.class, Order.class));
Then the clients inject Factory and use it just like they do in your example.
You're typically going to inject things that take some amount of effort to construct. If you're just injecting an int field, you'd be better off just calling a setter method on the object (that has some of it's more complex dependencies injected). Also, if a fields changes frequently, as implied by a field called "status", then it's also not a good candidate for injection.
Related
I am attempting to implement dependency injection in a class that is inherited from a base abstract class, and I get the following error: "javax.enterprise.inject.spi.DeploymentException: It's not possible to automatically add a synthetic no-args constructor to an unproxyable bean class. You need to manually add a non-private no-args constructor to com...ExampleIntegrationProvider in order to fulfill the requirements for normal scoped/intercepted/decorated beans."
From what I researched, it seems that this happens because classes that are annotated with normal scoped beans such as #ApplicationScoped for example, need a non-private constructor without arguments, so that CDI can create a proxy of that class when it is injected in lazy mode. I was a bit surprised to find out, as I've never had problems with code like this:
#ApplicationScoped
public class UserService {
private final UserRepository userRepository;
#Inject
public UserUseCase(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User findById(long id) { ... }
}
Even though Quarkus magically adds a synthetic no-args constructor, how could it overcome the final field UserRepository? There would be a problem with its initialization as it needs to receive a value, I imagine it might end up being passed a null value..
Anyway, going straight to my case, here's an example of my current situation, with 3 important base classes and 1 implementation for a "Example" partner:
PartnerIntegration.java
#MappedSuperclass
public abstract class PartnerIntegration {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
// other common fields ...
}
PartnerIntegrationRepository.java
public interface PartnerIntegrationRepository<I extends PartnerIntegration> extends PanacheRepository<I> {
// common methods ...
}
PartnerIntegrationProvider.java
public abstract class PartnerIntegrationProvider<I extends PartnerIntegration> {
protected final PartnerIntegrationRepository<I> partnerIntegrationRepository;
protected PartnerIntegrationProvider(PartnerIntegrationRepository<I> partnerIntegrationRepository) {
this.partnerIntegrationRepository = partnerIntegrationRepository;
}
// code ...
}
And finally the final implementation ExampleIntegrationProvider.java:
#ApplicationScoped
public class ExampleIntegrationProvider extends PartnerIntegrationProvider<ExampleIntegration> {
#Inject
public ExampleIntegrationProvider(ExampleIntegrationRepository exampleIntegrationRepository) {
super(exampleIntegrationRepository);
}
// code ...
}
The abstract class PartnerIntegrationProvider is not annotated with any scope as I did not consider it necessary since it only receives the PartnerIntegrationRepository interface and not a concrete repository. But ExampleIntegrationProvider receives a concrete repository that is implementing that interface, so I annotated it with #ApplicationScoped to be able to inject the concrete repository with #Inject. But this generated that error.
I tried creating a public constructor method that passes the null parameter to the parent class, and the error disappeared, but this ends up polluting my code, since I do not want to allow that class to be instantiated without receiving a repository, so I removed the #ApplicationScoped and #Inject annotations from ExampleIntegrationProvider and created that class to produce the instance that will be injected from it:
ExampleIntegrationProviderBean.java
#Dependent
public class ExampleIntegrationProviderBean {
private static ExampleIntegrationProvider INSTANCE;
private final ExampleIntegrationRepository exampleIntegrationRepository;
#Inject
public ExampleIntegrationProviderBean(ExampleIntegrationRepository exampleIntegrationRepository) {
this.exampleIntegrationRepository = exampleIntegrationRepository;
}
#Produces
public ExampleIntegrationProvider exampleIntegrationProvider() {
return INSTANCE == null ?
(INSTANCE = new ExampleIntegrationProvider(exampleIntegrationRepository)) : INSTANCE;
}
}
But the number of partners may grow quickly, I wouldn't like to have to create other classes like this one to produce the instances, and even if it was just one partner, it doesn't seem like a very elegant solution...
Does anyone have any ideas on how I can resolve this in a better way?
In one of my controller
#Autowired
private Map<String, ABC> abcMap;
now I want mock it in one of the unit test but I always get null pointer exception.
This map contains implementations of ABC abstract class.
Can anyone suggest a possible solution?
I'm not sure what Unit test Framework you are using but there are ways of making it inject the mock details. You'll have to give us more information before before we can answer.
Personally I don't much like Autowired private fields, so at the risk of answering a different question can I suggest you consider using an Autowired constructor instead. From Springs POV it won't make a difference, your object will be create and all the appropriate data wired in. (OK, there is a slight change in the order things are done, but generally you won't notice). You will have to write a constructor to copy the constructor parameters to private fields, but:
Those fields could be made final, which could make your class safer
Your Unit tests wont need any 'magic' to initialise the Autowired fields - just pass parameters
If you refactor you class to remove add/remove/modify an Autowired field then you have to remember to change your test code. With an Autowired constructor you test code has to be changed or it won't compile, and your IDE might even help you do it.
Update
The Autowired constructor alternative looks something like:
#Controller
class MyClass {
private final Class1 bean1;
private final Object value2;
#Autowired
MyClass(Class1 bean1, Class2 bean2) {
this.bean1 = bean1;
this.value2 = bean2.getValue();
}
}
Keys points are:
The class has just one constructor and it requires parameters.
The fields are not annotated #Autowired, because Spring is not assigning values to them; the constructor does that.
The constructor IS annotated as #Autowired to tell Spring to pass the beans as parameters
The first parameter is stored in a final variable - you code can't accidentally over write it, so your code is safer
In my example the second parameter is only used in the constructor, so we don't have to store it as a field in your controller. I often to this if the Bean is an object that passes configuration around.
A No-argument constructor is not required
At test time your code will have to pass parameters to the class.
Your test code will look something like:
class MyClassTest {
private Class1 bean1;
private Class2 bean2;
private MyClass objectUnderTest;
#Before
public void setUp() throws Exception {
bean1 = mock(Class1.class);
bean2 = mock(Class2.class);
// Train mocks here
objectUnderTest = new MyClass(bean1, bean2)
}
#Test
public void myTest() {
// Do something with objectUnderTest
}
}
Key points are:
There are no #MockBean annotations
The Unit test is only using the API that your Controller bean defines; No black magic is required
It's not possible to create a MyClass with out providing the required data. This is enforced by the compiler
I think you can try it.
The sample of code:
public interface Animal {
}
#Service
public class Cat implements Animal{
}
#Service
public class Dog implements Animal{
}
#Service
public class Clinic {
#Autowired
private final Map<String, Animal> animalMap = new HashMap<>(2);
}
Sample of test
#Configuration
public class TestEnvConfig {
#Bean
public Clinic create(){
return new Clinic();
}
#MockBean // you can do it without mock or use #ComponentScan
Dog dog;
#MockBean
Cat cat;
}
#SpringBootTest(classes = TestEnvConfig.class)
#RunWith(SpringRunner.class)
public class ClinicTest {
#Autowired
private Clinic clinic;
}
I have this beautiful scenery in front of me including JSF, jUnit(4.11) and Mockito(1.10.19):
#ManagedBean
#ViewScoped
public class UserAuth implements Serializable {
private List<UserRole> roleList;
private LocalChangeBean localChangeBean;
public UserAuth() {
roleList = new ArrayList<UserRole>();
localChangeBean = (LocalChangeBean) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("localChangeBean");
setLocalChangeBean(localChangeBean);
setRoleList(getLocalChangeBean().getRoleList());
//many other property setting and some JSF stuff
}
public boolean checkAuth() {
for (UserRole role : getRoleList()) {
if(role.getName().equals("SUPER_USER"))
return true;
}
return false;
}
}
//A hell of a lot more code, proper getters/setters etc.
Here is the test class:
public class UserAuthTest {
#Test
public void testCheckAuth() {
UserAuth bean = mock(UserAuth.class);
List<UserRole> mockRoleList = new ArrayList<UserRole>();
UserRole ur = mock(UserRole.class);
when(ur.getName()).thenReturn("SUPER_USER");
mockRoleList.add(ur);
when(bean.getRoleList()).thenReturn(mockRoleList);
assertEquals(true, bean.checkAuth());
}
The thing is; UserRole class is not reachable by me, it's another part of the project. It doesn't have a no-argument constructor and the existing constructor requires other unreachable classes etc. Thus I can't instantiate it. In these circumstances, all I want to do is to make that mock UserRole object behave such as returning the needed String when it's getName() method gets called.
But obviously; when I try to add that UserRole mock object into the List of UserRoles, the behavior that I tried to define is not stored with the object. And yes, the code looks pretty funny in its current stance. Though I left it there to learn what should I do to achieve this simple, little goal of mine.
Post-Edit:
I couldn't manage the problem without changing the original bean, though I followed Jeff's suggestion below and it worked well as a strategy of isolation. I did not mark it as the best answer since the question was "How to mock an unreachable third party class?" (in the current example its the UserRole class) Eventually the noob me understood that "Mocking an unreachable third party class is no different than mocking any other class".
Here is how I managed it:
#ManagedBean
#ViewScoped
public class UserAuth implements Serializable {
private List<UserRole> roleList;
private LocalChangeBean localChangeBean;
public UserAuth() {
//the actual constructor including all JSF logic, highly dependent
}
UserAuth(List<UserRole> roleList) {
setRoleList(roleList);
//package private test-helper constructor which has no dependency on FacesContext etc.
}
public boolean checkAuth() {
for (UserRole role : getRoleList()) {
if(role.getName().equals("SUPER_USER"))
return true;
}
return false;
}
}
And here is the test class (attention to the iterator mock, it has the whole trick):
public class UserAuthTest {
private UserRole mockRole;
private Iterator<UserRole> roleIterator;
private List<UserRole> mockRoleList;
private UserAuth tester;
#SuppressWarnings("unchecked")
#Before
public void setup() {
mockRoleList = mock(List.class);
mockRole = mock(UserRole.class);
roleIterator = mock(Iterator.class);
when(mockRoleList.iterator()).thenReturn(roleIterator);
when(roleIterator.hasNext()).thenReturn(true, false);
when(roleIterator.next()).thenReturn(mockRole);
tester = new UserAuth(mockRoleList);
}
#Test
public void testCheckAuth(){
when(mockRole.getName()).thenReturn("SUPER_USER");
assertEquals("SUPER_USER expected: ", true, tester.checkAuth());
}
You don't need Mockito. A quick refactor will do this for you.
Your problem: Your code relies on a static call to FacesContext.getCurrentInstance() in your constructor, that is difficult to prepare or substitute out in tests.
Your proposed solution: Use Mockito to substitute out the FacesContext instance, the external context, or the session map. This is partly tricky because Mockito works by proxying out the instances, so without PowerMock you won't be able to replace the static call, and without a way to insert the mock into FacesContext or its tree, you have no alternative.
My proposed solution: Break out the bad call FacesContext.getCurrentInstance().getExternalContext.getSessionMap() into the default constructor. Don't call that constructor from tests; assume it works in the unit testing case. Instead, write a constructor that takes in the session map as a Map<String, Object>, and call that constructor from your tests. That gives you the best ability to test your own logic.
#ManagedBean
#ViewScoped
public class UserAuth implements Serializable {
// [snip]
public UserAuth() {
// For the public default constructor, use Faces and delegate to the
// package-private constructor.
this(FacesContext.getCurrentInstance().getExternalContext().getSessionMap());
}
/** Visible for testing. Allows passing in an arbitrary map. */
UserAuth(Map<String, Object> sessionMap) {
roleList = new ArrayList<UserRole>();
localChangeBean = (LocalChangeBean) sessionMap.get("localChangeBean");
setLocalChangeBean(localChangeBean);
setRoleList(getLocalChangeBean().getRoleList());
// [snip]
}
}
p.s. Another solution is to actually get the session map within the test and insert the value you need, but you have to be careful there not to pollute your other tests by installing something into a static instance that may persist between tests.
My class depends on some services which needs to take few parameters and then make network call, currently I am passing those parameters and then creating those services via a factory injected into my class. I need to inject those services as a dependency instead, I know that I can create providers for them but in most of the examples I see that the providers are often bound to the fixed values like serveraddres etc. but I need to give then values during run time.
Below is my example code:
public SomeClass {
private final SomeFactory someFactory;
#Inject
SomeClass(SomeFactory factory) {
someFactory = factory;
}
public Foo getFoo(String fooId) {
FooService fooService = someFactory.getFooService(fooId);
return fooService.getFoo();
}
}
What I need to do is:
public SomeClass {
private final FooService fooService;
#Inject
SomeClass(FooService fooService) {
this.fooService = fooService;
}
public Foo getFoo(String fooId) {
return fooService.getFoo();
}
}
Update 1
Making the use case more clear:
#Provides
#RequestScoped
public SomeService provideSomeService(Dep1 dep1, String code) throws IOException {
return new SomeService.Builder()
.withApplicationName("Foo")
.setCode(code)
.build();
}
Here, code can be null by default and when needed I can give some value in it.
Can I somehow pass arguments to the provider before its created?
If you have a binding for your value (here, code is a String without a binding annotation), then your Update 1 is exactly what the code would look like.
In practice, there are a few differences:
Constants like int and String values are generally annotated with a binding annotation, either #Named or a custom annotation.
If you need to inject a value into an object graph after Guice initialization, but have a deep enough object graph that dependency injection is still a good idea, you can create a child injector. This way you can make a #Named("code") String accessible within one action or object, but not across your entire Guice application.
If your value for code is dynamic enough that it can't be provided through Guice as a key of its own, then you'll have to pass it in using a factory of some sort. For a Builder-based object, I'd say that your SomeFactory implementation is the best that I would come up with in your case.
If you don't need to use a Builder, and can let Guice create the object based on your fields or constructor parameters, you can code-generate a Factory.
Guice can generate a factory for you through FactoryModuleBuilder, in a feature known as "assisted injection".
Google's other tool, AutoFactory, will code-generate a factory implementation that works in both Guice and Dagger. (It's bundled as "Auto", which includes a model object generator called AutoValue that also generates annotation implementations.)
I put a small demonstration of a child injector and assisted injection in my other SO answer here.
The best approach here is to parameterize the module and pass the parameter through to a provider that you create at runtime:
public class MyModule extends AbstractModule {
private final String code;
public MyModule(String code) {
this.code = code;
}
#Override public void configure() {
Provider<Dep1> depProvider = getProvider(Dep1.class);
bind(SomeService.class)
.toProvider(() -> new SomeService.Builder()
.withApplicationName("Foo")
.withDep(depProvider.get())
.setCode(code)
.build())
.in(RequestScoped.class);
}
}
I got the following problem. I want to create SomeObject. This object consists of various nested objects NestedObject1, NestedObject2, ... I created mappers to create those nested objects Mapper1 to create NestedObject1, Mapper2 to create NestedObject2, and so on. Those Mappers call a huge amount of setters, and some of them need information from some entites from the db (and some don't). This is the problem in the java language:
public class MyClass {
#Inject
private MyDao dao;
#Inject
private Mapper1 mapper1;
#Inject
private Mapper2 mapper2;
#Inject
private Mapper3 mapper3;
#Inject
private Mapper4 mapper4;
#Inject
private Mapper5 mapper5;
public SomeObject map(Integer id) {
SomeEntity entity = dao.findById(id);
SomeObject someObject = new SomeObject();
someObject.setNestedObject1(mapper1.map(entity));
someObject.setNestedObject2(mapper2.map());
someObject.setNestedObject3(mapper3.map(entity));
someObject.setNestedObject4(mapper4.map(entity));
someObject.setNestedObject5(mapper5.map());
return someObject;
}
}
I am thinking of the following refactoring:
Make an interface Mapper and have all mappers implement this. Then I could inject the List of mappers. It would be pretty easy to add or remove on mapper, without touching MyClass. I think this is a good idea but the problem is the MyDao. Instead of one DB access I would then need 3.
The interface would then look like
public interface Mapper {
public void map(SomeObject someObject);
}
Mapper1 would look like
public class Mapper1 implements Mapper {
private static final Integer VALUTA = 1;
#Inject
private MyDao dao;
#Override
public void map(SomeObject someObject) {
SomeEntity entity = dao.findById(id); // and I have no idea what the id is
NestedObject1 nestedObject1 = new NestedObject1();
nestedObject1.setSomeField(entity.getSomething());
nestedObject1.setSomeOtherField(VALUTA);
someObject.setNestedObject1(nestedObject1);
}
}
id is unknown in this context. Include id in the signature? I have no idea...
Mapper3 and Mapper4 would have to look up the entity as well.
I was thinking about an abstract class which will look for the entity in the BeforeClass method, but I think this still get's called multiple times.
Btw: I know the title sucks, please feel free to rename it.