1

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?

8
  • You have no return type in method Commented Dec 27, 2016 at 14:30
  • A return type is missing in the code. Commented Dec 27, 2016 at 14:30
  • Thanks, corrected Commented Dec 27, 2016 at 14:30
  • Where does config come from? Commented Dec 27, 2016 at 14:31
  • From database. ClientConfig does not depend on clientType Commented Dec 27, 2016 at 14:35

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

The question is how to get rid of this ugly select which will be used here as well inside OAuthClientFactory#createOAuthClient
2

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;
}

4 Comments

OK, but this requires to have a list of instances and I need to instantiate on demand with constructor arguments.
So you don't want to instantiate using spring ?
You use reflection to create instances : you may create a Map assiociating name to class, after this you invoke using reflection.
That's what I'm doing. clientClass.getConstructor(ClientConfig.class).newInstance(config); I just want to know if Spring can do it more gracefully.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.