Throw exception if bean is defined twice? - java

In my project I have different services. Each service can define its own Permissions. For each permission, a bean will created. This way, the Authorization service can inject all available permission, without actually knowing them.
The Permission definition of ServiceA will look like this:
#Configuration()
public class ServiceAPermissions extends Permissions {
private static final String BASE = "servicea";
public static final String SERVICEA_READ = join(BASE, READ);
public static final String SERVICEA_WRITE = join(BASE, WRITE);
#Bean()
Permission getReadPermission() {
return new Permission(SERVICEA_READ);
}
#Bean()
Permission getWritePermission() {
return new Permission(SERVICEA_WRITE);
}
}
ServiceB will define the following Permissions:
#Configuration()
public class ServiceBPermissions extends Permissions {
private static final String BASE = "serviceb";
public static final String SERVICEB_READ = join(BASE, READ);
#Bean()
Permission getReadPermission() {
return new Permission(SERVICEB_READ);
}
}
Obviously, this will end in a name clash of the defined beans as I have defined a bean with the name getReadPermission twice. If course I can name the methods like getServiceAReadPermission so they will be distinguished, but this only a convention, which might be ignored.
In this situation, Spring doesn't notify me about the duplicate definition, it simply will just instantiate one and ignore the other definition. Is there a way to tell Spring to throw an Exception, if a bean is defined twice? This way one would be always aware of a duplicate definition.
Alternatively, is there a way to tell spring, that it should use a random bean name instead of the method signature? I know that I can give each bean a name manually #Bean(name = "A name"), but I like to avoid that, as a dev will not be forced to do so and still might forget it.

That design does not seem very logical. A bean is supposed to be available only once, you're using it differently.
I'd suggest to provide a PermissionFactory-Bean which does what you need, along the line of
#Component
public class PermissionFactory {
public Permission createFactory() {
// create A or B permission randomly, as you wanted
}
}

Related

How to use Spring ObjectProvider with more than one bean definition

I am using an ObjectProvider to create instances of a prototype scope bean using the getObject() method. Something like this
#Configuration
class Config {
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
SomeType typeOne() {
return new SomeType();
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
SomeType typeTwo(String param) {
return new SomeType(param);
}
}
#Service
class Service {
private ObjectProvider<SomeType> objectProvider;
public Service(
ObjectProvider<SomeType> objectProvider) {
this.objectProvider = objectProvider;
}
#Override
public String performAction() {
return getSomeType().doAction();
}
private SomeType getSomeType() {
return objectProvider.getObject();
}
}
But since there are two beans of the type that the ObjectProvider is trying to get (SomeType), I get a NoUniqueBeanDefinitionException. (And I do need the other bean of the same type, because that one I need to provide parameters using objectProvider.getObject(Object... params) )
Playing around and debugging Spring I saw that if you name your ObjectProvider exactly like your bean then it works, something like:
private ObjectProvider<SomeType> typeOne;
My question is, are there other ways to use an ObjectProvider and manage to resolve ambiguity, or is this approach the way to go?
Short answer is you just need to properly qualify the ObjectProvider you want injected, like this:
public Service(#Qualifier("typeOne") ObjectProvider<SomeType> objectProvider) {
this.objectProvider = objectProvider;
}
With Spring configuration, when you specify a bean via a method, and don't specify it's name with #Bean("NAME"), Spring uses the method name as the bean name.
Similarly, when injecting a bean that is not specified by #Qualifier("NAME"), Spring takes the injected variable as the name, if that don't exists or is not unique, you might get some exceptions informing you about this (like the NoUniqueBeanDefinitionException you facing).
So, if you match the bean name and the injected variable name you don't need to be more specific, but if you don't, #Qualifier is there to your rescue :D

What is the correct Bean's proxyMode for allowing concurrency in Spring?

I am building a library based on Spring Framework and I want to allow users invoke Library's methods in parallel.
In my main class I autowire Service class:
#Autowired
private ExportListCommand exportList;
And that's implementation for Library's method:
public ResponseContainer<ExportListResponse> exportList(ExportListOptions options) {
exportList.setoAuthClient(oAuthClient);
ResponseContainer<ExportListResponse> result = exportList.executeCommand(options);
return result;
}
ExportListCommand is defined as a Bean:
#Bean
#Scope("prototype")
public ExportListCommand exportList() {
return new ExportListCommand();
}
When I as a Library user run 2 exportList's methods in parallel Spring creates only single ExportListCommand bean since it autowired only once. But in reality I need 2 independent ExportListCommand beans. I also tried to change #Scope(value="prototype") to #Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS), but that also does not work as I need: Spring creates ExportListCommand bean for each method invocation and I lose oAuthClient value since I get new object.
I made it work only with AnnotationConfigApplicationContext.getBean() approach which I would like to avoid.
What my options are? Thanks.
I believe you are looking to work with a 'factory' object.
There are two primary ways I would consider this from a Spring standpoint.
The 'Java' way: Create a factory object that will return instances of ExportListCommand
This factory would look something like this:
class ExportListCommandFactory {
ExportListCommand newInstance() {
return new ExportListCommand();
}
}
and would be used in your method like this:
#Autowire
private ExportListCommandFactory commandFactory;
public ResponseContainer<ExportListResponse> exportList(ExportListOptions options) {
final ExportListCommand exportList = commandFactory.newInstance();
exportList.setoAuthClient(oAuthClient);
ResponseContainer<ExportListResponse> result = exportList.executeCommand(options);
return result;
}
Of course, doing this would require that you change your configuration to contain a bean that is an ExportListCommandFactory rather than an ExportListCommand.
Alternatively, you could consider...
The 'Spring' way: Use FactoryBean
The only thing you should need to do here is, in your main class, #Autowire a FactoryBean<ExportListCommand> instead of the ExportListCommand, and in your method where you need to invoke the method, consult the factory to get your instance.
#Autowire
private FactoryBean<ExportListCommand> commandFactory;
public ResponseContainer<ExportListResponse> exportList(ExportListOptions options) {
final ExportListCommand exportList = commandFactory.getObject();
exportList.setoAuthClient(oAuthClient);
ResponseContainer<ExportListResponse> result = exportList.executeCommand(options);
return result;
}
You shouldn't need to change your configuration, as FactoryBean is a special bean that will consult the ApplicationContext/BeanFactory for the instance at each invocation of getObject().

Sharing state between step definitions in Cucumber

I have 4 step definition classes and a set of domain object classes.
My first step definition class looks like this:
public class ClaimProcessSteps {
Claim claim;
public ClaimProcessSteps(Claim w){
this.claim = w;
}
#Given("^a claim submitted with different enrolled phone's model$")
public void aClaimSubmittedFromCLIENTSChannelWithDifferentEnrolledPhoneSModel() throws Throwable {
claim = ObjMotherClaim.aClaimWithAssetIVH();
}
}
My Claim class looks like this:
public class Claim {
private String claimType;
private String clientName;
private Customer caller;
private List<Hold> holds;
public Claim() {}
public Claim(String claimType, String clientName, Customer caller) {
this.claimType = claimType;
this.clientName = clientName;
this.caller = caller;
}
public String getClaimType() {
return claimType;
}
My second step definition class looks like:
public class CaseLookupSteps {
Claim claim;
public CaseLookupSteps(Claim w){
this.claim = w;
}
#When("^I access case via (right|left) search$")
public void iAccessCaseInCompassViaRightSearch(String searchVia) throws Throwable {
System.out.println(claim.getClaimType());
}
I've already imported the picocontainter dependency in my POM.XML and I am getting the following error.
3 satisfiable constructors is too many for 'class java.lang.String'. Constructor List:[(Buffer), (Builder), ()]
None of my step definition classes constructors receive primitives as arguments. Does anyone have any clue as to why I am still getting that error? Could it be my business object constructor that does expect a String in its constructor?
Thanks in advance for any help.
Picocontainer looks over not only your step definition classes to resolve dependencies. It also looks over all classes that your steps definitions depend on.
In this case, it's trying to resolve the dependencies for your non-default Claim constructor.
public Claim(String claimType, String clientName, Customer caller) {
...
}
According to this issue there's no way to solve this other than keeping only default constructors in all your dependencies.
Assuming your scenario looks like this:
Given some sort of claim
When I lookup this claim
Then I see this claim
Currently your test is missing the setup step of the claim.
So rather then directly sharing the claim object between steps you should create a ClaimService class with only the default constructor. You can inject this service into your step definitions.
Once you have injected the service, you can use it in the step definition of Given some sort of claim to callclaimService.createSomeSortOfClaim() to create a claim. This claim can be created in memory, in a mock db, actual db, or other persistence medium.
In When I lookup this claim you then use claimService.getClaim() to return that claim so you can use its type to search for it.
Doing it this way you'll avoid the difficulty of trying to make the DI container figure out how it should create the claim under test.

Java How to make object use it's implemented static interface method

I have an class with a static interface within it.
public class UserInfo {
private Store userInfoStore;
public static interface Store {
UserInfo save(UserInfo userInfo);
}
public UserInfo save() {
if (userInfoStore == null) return null;
return userInfoStore.save(this);
}
}
I then have an object which implements the above object's interface
public class UserAuditService implements UserInfo.Store {
#Override
public UserInfo save(UserInfo userInfo) {
// code that persists object to disk
}
}
Now say I'm creating an instance of the UserInfo object somewhere else in my application. How do I reference the save method implemented in the UserAuditService class?
UserInfo userInfo = new UserInfo();
??? - Not sure what to do here.
If save method is what you want to call then do the following:
UserInfo userInfo = new UserInfo();
UserInfo.Store userStore = new UserAuditService();
userStore.save(userInfo);
This is one way of using the implemented method.
You mean you don't want to hardcode the UserAuditService class, because there may be many implementations in the future?
There are many solutions, it's what the dependency injection is all about.
You may use Spring or other dependency injection framework, and configure the class to use in xml (or by annotations).
You may do it by hand, for example using constructor dependency injection (you add field of type UserInfo.Store to the UserInfo class, and assign to it a class passed as parameterin a constructor of UserInfo).
Another option is setter dependency injection - you have the same field in UserInfo, but you set it in a setter called from some place after the UserInfo was created.
This makes it clear what happens, but requires to pass the dependencies all the way from the place you configured it to the place they are used, that's why people use dependency injection frameworks to cut the boilerplate.

How to pass parameters dynamically to Spring beans

I am new to Spring.
This is the code for bean registration:
<bean id="user" class="User_Imple"> </bean>
<bean id="userdeff" class="User"> </bean>
and this is my bean class:
public class User_Imple implements Master_interface {
private int id;
private User user; // here user is another class
public User_Imple() {
super();
}
public User_Imple(int id, User user) {
super();
this.id = id;
this.user = user;
}
// some extra functions here....
}
and this is my main method to perform action:
public static void main(String arg[]) {
ApplicationContext context = new ClassPathXmlApplicationContext("/bean.xml");
Master_interface master = (Master_interface)context.getBean("user");
// here is my some operations..
int id = ...
User user = ...
// here is where i want to get a Spring bean
User_Imple userImpl; //want Spring-managed bean created with above params
}
Now I want to call this constructor with parameters, and these parameters are generated dynamically in my main methods. This is what I mean by I want to pass dynamically – not statically, like declared in my bean.config file.
If i get you right, then the correct answer is to use getBean(String beanName, Object... args) method, which will pass arguments to the bean. I can show you, how it is done for Java based configuration, but you'll have to find out how it is done for an XML based configuration.
#Configuration
public class ApplicationConfiguration {
#Bean
#Scope("prototype") // As we want to create several beans with different args, right?
String hello(String name) {
return "Hello, " + name;
}
}
// and later in your application
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
String helloCat = (String) context.getBean("hello", "Cat");
String helloDog = (String) context.getBean("hello", "Dog");
Is this what are you looking for?
UPDATE
This answer gets too much upvotes and nobody looks at my comment. Even though it's a solution to the problem, it is considered as a Spring anti-pattern and you shouldn't use it! There are several different ways to do things right using factory, lookup-method, etc.
Please use the following SO post as a point of reference:
How to instantiate Spring managed beans at runtime?
Please have a look at Constructor injection.
Also, Have a look at IntializingBean and BeanPostProcessor for other life cycle interception of a springbean.
I think the answers proposed above to use constructor injection/setter injection doesn't work perfectly for the use case you are looking for.
Spring more or less takes static argument values for constructors/setters. I don't see a way to dynamically pass values to get a Bean from Spring Container.
However, if you want to get instances of User_Imple dynamically, I would recommend using a factory class User_Imple_Factory
public class User_Imple_factory {
private static ApplicationContext context =new ClassPathXmlApplicationContext("/bean.xml");
public User_Imple createUserImple(int id) {
User user = context.getBean("User");
return new User_Imple(id, user);
}
}
Constructor injection can help you. In this case you may need to generate a POJO with ID and user as its attributes and pass POJO to constructor. In constructor injection in config file you can refer this constructor with pojo as reference. So you will be handle the dynamic value of data in ID and User.
Hope this helps !!
Perhaps letting the User_Imple be an ordinary Pojo (instead of a Spring bean) will solve your problem?
<!-- Only use User as a Spring Bean -->
<bean id="userdeff" class="User"></bean>
Java:
public static void main(String arg[])
{
ApplicationContext context =new ClassPathXmlApplicationContext("/bean.xml");
User user = context.getBean(User.class);
int id = // dynamic id
Master_interface master = new User_Imple(id, user);
}

Categories

Resources