Oleg Mikhailov
Oleg Mikhailov

Reputation: 6081

Spring: instantiate a class depending on String parameter

I have a syntax similar to this in my spring application:

public OAuthClient getOAuthClient(String clientType, ClientConfig config){
    switch (clientType) {
        case "google":
            return new GoogleOAuthClient(config);
        case "facebook":
            return new FacebookOauthClient(config);
        case "linkedIn":
            return new LinkedInOauthClient(config);
        //... more clients
        default:
            return new BasicOauthClient(config);
    }
}

How to manage such instantiation with Spring xml-configuration?

Upvotes: 1

Views: 1413

Answers (2)

Ken Bekov
Ken Bekov

Reputation: 14015

It is little bit unclear what you going to do. But if you would like to have OAuthClient as managed bean and its creation based on some conditions, you can use factory. First create factory class:

public class OAuthClientFactory{
    public OAuthClient createOAuthClient(String clientType, ClientConfig config){
       //Conditional creation logic...
    } 
}

Now in xml-configuration declare beans:

<bean id="authClientFactory" class="com.somepackage.OAuthClientFactory"/>
<bean id="clientConfig" class="com.somepackage.ClientConfig"/>

<bean id="authClient" class="com.somepackage.OAuthClient " factory-bean="authClientFactory" 
  factory-method="createOAuthClient">
    <constructor-arg value="google"/>
    <constructor-arg ref="clientConfig"/>
</bean>

ClinetConfig also have to be managed bean for pass it as parameter into factory method. For make example simpler I just declared it as bean, but in real code you should decide how to create it.


According to your last comments you need to instantiate client instances on demand. And you would like to avoid any conditional operations and make it by "spring way". Then you should register all types of clients as bean with corresponding name.

If you need to create new instance every time you request for new client, you should declare it as prototype bean:

...
<bean id="googleClient" class="com.somepackage.GoogleOAuthClient" scope="prototype"/>
<bean id="facebookClient" class="com.somepackage.FacebookOauthClient" scope="prototype"/>
...

Or if you need just one (singleton) instance of every requested client declare it as lazy-init:

...
<bean id="googleClient" class="com.somepackage.GoogleOAuthClient" lazy-init="true"/>
<bean id="facebookClient" class="com.somepackage.FacebookOauthClient" lazy-init="true"/>
...

In both cases instances of client will be created only by demand. Now you can get instance of client by requesting from ApplicationContext:

@Service
public class SomeService{

    @Autowired
    private ApplicationContext context;

    public void SomeMethod(){
        ClientConfig config = ... //obtain client config
        GoogleOAuthClient client = (GoogleOAuthClient)context.getBean("googleClient", config);
    }
}

Or if you don't use annotation based injection, then implement ApplicationContextAware interface to get ApplicationContext.

Upvotes: 3

Pascal Heraud
Pascal Heraud

Reputation: 373

You can autowire the list of classes implementing or extending OAuthClient. You'll be able to select the good one if you have a "getName()" method for instance :

@Autowired
List<OAuthClient> clients;
public OAuthClient getOAuthClient(String clientType, ClientConfig config){
     foreach (OAuthClient client : clients) {
         if (client.getName().equals(clientType)) {
            return client;
         }
    }
     // Return null or throw exception
     return null;
}

Upvotes: 2

Related Questions