2

I have a common situation: I have a scenario where object creation is handled by a builder. e.g.

Class Client; // Creates a builder object.
Class Builder; // Can be used to set the desired params and then invoke build on it to return Service object.
e.g.-
client.createBuilder().withDefaultBinding(new StandardBinder())
            .withDefaultMetricsFactory(new StandardMetricsFactory())
            .withCacheSolution(cacheSolution)
            .build();

However, Builder doesn't have standard setters. It performs some tasks and then sets the result into an internal object of Builder, so they can't be treated as properties as is.

I've read through: Spring: Using builder pattern to create a bean

I want to invoke the builder to retrieve the final object completely using Spring XML configuration. I don't want to create a factory myself - I want to know if there is a way I can use an out-of-the-box Spring XML configuration to generate a service object in the above scenario? My understanding of Spring gives me the impression that this can be done by invoking a chain of setter methods (not setting the properties explicitly) on the builder objects and finally invoking a build to get the service object. If this is possible how would it be achieved?

Community
  • 1
  • 1
rajneesh2k10
  • 1,550
  • 3
  • 12
  • 24

3 Answers3

8

There's no way to do this out-of-the-box with XML. Define a FactoryBean with appropriate properties (setters) for all the values you need and declare a bean of that custom FactoryBean type.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
2

I've made it work when I wasn't able to "fix" the builder, and was only able to adjust config, not code.

  • Define a bean that uses "client" as a factory bean and "createBuilder" as the factory method.

  • Define another bean that uses that bean as a factory bean and "withDefaultBinding" as the factory method.

  • Define another bean that uses that bean as a factory bean and "withDefaultMetricsFactory" as the factory method.

  • Define another bean that uses that bean as a factory bean and "withCacheSolution" as the factory method.

  • Finally define your built bean that uses that bean as a factory bean and "build" as the factory method.

  • All but the last bean will actually point to the same object in memory, but that doesn't really matter.

Unheilig
  • 16,196
  • 193
  • 68
  • 98
0

I did have a similar case:

@Value("${some.property}") 
String someProperty

@Bean
public JwtDecoder jwtDecoder() {
    NimbusJwtDecoder.withJwkSetUri(someProperty).build();
}

Here's what I've done:

<bean id="jwtDecoder" class="org.springframework.security.oauth2.jwt.NimbusJwtDecoder" factory-bean="jwtDecoderBuilder" factory-method="build"/> <!-- factory-bean -->

<bean id="jwtDecoderBuilder" class="org.springframework.security.oauth2.jwt.NimbusJwtDecoder" factory-method="withJwkSetUri">  <!-- NO factory-bean -->
    <constructor-arg name="jwkSetUri" value="${some.property}"/>
</bean>

NimbusJwtDecoder source code:

https://github.com/spring-projects/spring-security/blob/5.2.2.RELEASE/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java

Eugene Maysyuk
  • 2,977
  • 25
  • 24