Search code examples
javacxf

Set (Spring) bean property programmatically


I am currently trying to setup Apache CXF with OAuth authentication. I am at the point that the OAuthDataProvider needs to start providing Client information. In the documentation is stated that you can configure the dataProvider with the following xml;

<!-- implements OAuthDataProvider -->
<bean id="oauthProvider" class="oauth.manager.OAuthManager"/>

<bean id="accessTokenService" class="org.apache.cxf.rs.security.oauth2.services.AccessTokenService">
  <property name="dataProvider" ref="oauthProvider"/>
</bean>

<jaxrs:server id="oauthServer" address="/oauth">
   <jaxrs:serviceBeans>
      <ref bean="accessTokenService"/>
  </jaxrs:serviceBeans>
</jaxrs:server>

Now I am not using Spring, using the org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet and having a javax.ws.rs.core.Application class provide the classes/singletons and properties required.

Now the question is; Is there a way to configure this dataProvider property programmatically without having to use Spring? Or even in the web.xml for example?

Edit

I found I can solve it by extending the AccessTokenService class and doing the following.

class CustomAccessTokenService extends AccessTokenService {

    public CustomAccessTokenService() {
        setDataProvider(new OAuthManager());
    }
}

but that does not seem like a very elegant solution.

Simplified version of Application implementation

@ApplicationPath("/")
class ServiceApplication extends Application {

    private final Set<Class<?>> _classes = new HashSet<>();

    public ServiceApplication() {
        _classes.add(...)
        _classes.add(AccessTokenService.class)
        ...
    }

    @Override
    public Set<Class<?>> getClasses() {
        return _classes;
    }
}

Solution

  • Override the getSingletons() method of Application - see below:

    OK, after that response, you can do this (I pulled this from a project I have, I use the methods to determine API keys to inject into my REST services):

    @ApplicationPath("/rest")
    public class RESTApplication extends Application {
    @Override
    
        private SingletonServiceObject getMySingletonService(){
            ... Do whatever to setup your singleton ...
        }
    
        public Set<Object> getSingletons() {
            L.info("Setting up REST - getSingletons()");
            Set<Object> singletons = new HashSet<Object>();
            try {
                singletons.add(getMySingletonService());
                singletons.add(new GeoService());
            } catch (IOException e) {
                throw new ProjectRuntimeException("Error creating service!", e);
            }
            L.info("Finished REST - getSingletons()");
            return singletons;
        }
    }
    

    After seeing your edit, you can do the following:

    WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
    AccessTokenService myBean = context.getBean(AccessTokenService.class);
    myBean.setDataProvider(...whatever...);
    

    Note that there is also a way to provide instances of beans from your Application class. I don't remember how to do that off-hand, but either way should work.

    • Pre edit answer is below *

    All the XML means is accessTokenService.setDataProvider(oauthProvider), so have your Application class call that method on the accessTokenService you are creating.