1
votes

I am trying to convert a Spring application (for the most part) to a Spring Boot application. In the app, I have an HTTP basic filter that collects a username and password, this is then passed as variables in a DataSource implementation.

In this DataSource, the getConnection() method is so:

@Override\n public Connection getConnection() throws SQLException {
Statement  stmt = null;

try {
    ConnectionWrapper connection = this.authenticatedConnection.get();
    if (connection == null) {
        connection = new ConnectionWrapper(this.dataSource.getConnection());

        StringBuilder command;

        // The CONNECT command allows indicating a user name, a password
        // and a database to initiate a
        // new session in the server with a new profile.
        command = new StringBuilder("CONNECT USER ").append(this.parameters.get().get(USER_NAME)).append(" PASSWORD ")
                .append("'").append(this.parameters.get().get(PASSWORD_NAME)).append("'").append(" DATABASE ")
                .append(this.parameters.get().get(DATA_BASE_NAME));

        this.authenticatedConnection.set(connection);

        stmt = connection.createStatement();
        stmt.execute(command.toString());
    }

    return connection;
} catch (final SQLException e) {...`

(With \n as a new line due to StackOverflow formatting issues)

In Spring, I am able to implement @Autowired Private DataSource dataSource without a problem. In Spring Boot, as I understand it, the Object needs to be a Bean to use @Autowired, but when I add @Bean before this implemented DataSource I get "The annotation @Bean is disallowed for this location"

How can I get it so that I can do a dataSource.getConnection(); and get a connection from the primary DataSource, or be able to Override the methods of the primary DataSource?

The way I see it, there are 4 possible solutions listed here in order of preference:

  1. Create a DataSource that is actually overwriting the spring.datasource' methods.
  2. Get this implementation "Beanified" so I can just @Autowired the dataSource again.
  3. I think I can skip the @Autowired and simply set this.dataSource = [unknown reference to spring.datasource defined in application.properties]
  4. Create another DataSource class ProgrammedDataSource configured with the spring.datasource properties, then set it as this.dataSource = new ProgrammedDataSource();

but my attempts at implementing any of these solutions have produced this question.

1
Do you understand the various stereotype annotations (that's a hint) that you can use to indicate a class is a Spring bean? - Abhijit Sarkar
Thanks for more Google searches. - MBudnick
I've narrowed it down to the @Repository annotation. I am working on it now and will provide an answer when I get it working. (If nobody else has acceptably responded.) - MBudnick
No matter what I try the this.dataSource from @Autowired private DataSource dataSource; is null. The application.properties settings are correct. - MBudnick
There is a plethora of examples on how to create a DataSource with Java config. - Abhijit Sarkar

1 Answers

1
votes

I figured it out. I didn't need to make the Bean there, although I am still not sure why I was not allowed to call @Bean before the DataSource, but regardless.

In the application I had:

public class ServiceApplication {

@Bean
@Primary
@ConfigurationProperties("spring.datasource")
 public DataSource dataSource(){
  return DataSourceBuilder.create().build();
 }

@Bean(name="AuthDataSource")
public DataSource authDataSource() {
        return new AuthDataSource();
}

public static void main(String[] args) {
    SpringApplication.run(ServiceApplication.class, args);
}

}

and in the controller I had:

@Controller
@RequestMapping("/service")
public class ServiceController {

      @Autowired
      public void MyBean(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = new JdbcTemplate(new AuthDataSource());
      } ...

However, since I was calling new AuthDataSource() inside that JdbcTemplate, it was not doing the Autowiring. Now the Controller looks like this and it works:

@Controller
@RequestMapping("/service")
public class ServiceController {

      @Autowired
      @Qualifier("AuthDataSource")
      private DataSource datasource;
      private JdbcTemplate jdbcTemplate;

      @Autowired
      public void MyBean(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = new JdbcTemplate(this.dataSource);
      } ...