2

Reading Pro Spring 5, an example that show Spring JDBC is using MySQL DB. I use the book source code. Here is the code

@Configuration
@PropertySource("classpath:db/jdbc2.properties")
@ComponentScan(basePackages = "com.apress.prospring5.ch6")
public class AppConfig {

    private static Logger logger = LoggerFactory.getLogger(AppConfig.class);
    @Value("${driverClassName}")
    private String driverClassName;
    @Value("${url}")
    private String url;
    @Value("${username}")
    private String username;
    @Value("${password}")
    private String password;

@Bean(destroyMethod = "close")
    public DataSource dataSource() {
        try {
            BasicDataSource dataSource = new BasicDataSource();
            dataSource.setDriverClassName(driverClassName);
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            return dataSource;
        } catch (Exception e) {
            logger.error("DBCP DataSource bean cannot be created!", e);
            return null;
        }
    }

jdbc2.properties

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/musicdb?useSSL=true
username=prospring5
password=prospring5

The test

public class AnnotationJdbcTest {

    private GenericApplicationContext ctx;
    private SingerDao singerDao;

    @Before
    public void setUp() {
        ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        singerDao = ctx.getBean(SingerDao.class);
        assertNotNull(singerDao);
    }

    @Test
    public void testFindAll() {
        List<Singer> singers = singerDao.findAll();
        assertTrue(singers.size() == 3);
        listSingers(singers);
        ctx.close();
    }

My MySQL instance already have the user prospring5 and the schema created and populated

enter image description here enter image description here

When I try to run AnnotationJdbcTest, I get this exception:

Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: Cannot create PoolableConnectionFactory (Access denied for user 'Mehdi'@'localhost' (using password: YES))
org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: Cannot create PoolableConnectionFactory (Access denied for user 'Mehdi'@'localhost' (using password: YES))
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:82)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:612)

As you can see the project is using my computer name 'Mehdi' instead of the one in the .properties file 'prospring5' . Why is That? and how Can I fix it?

You can yourself download the source code and run it from here: https://github.com/Apress/pro-spring-5 the project is: chapter6/spring-jdbc-annotations

EDIT: I printed the values as suggested by @STaefi and here is the output:

com.mysql.cj.jdbc.Driver
jdbc:mysql://localhost:3306/musicdb?useSSL=false
Mehdi
prospring5

Code

@Bean()
    public DataSource dataSource() {
        try {
            BasicDataSource dataSource = new BasicDataSource();
            dataSource.setDriverClassName(driverClassName);
            System.out.println(driverClassName);
            dataSource.setUrl(url);
            System.out.println(url);
            dataSource.setUsername(username);
            System.out.println(username);
            dataSource.setPassword(password);
            System.out.println(password);
            return dataSource;

First I tried setting the values at initialization and that was no good. but after I used username = "prospring5"; dataSource.setUsername(username); it worked. so what does this mean. why Spring cannot load the username like it successfully loaded the url and the password.

usertest
  • 2,140
  • 4
  • 32
  • 51
  • An early guess, maybe it has a problem finding and loading your properties file. Can you hard code the username and password to see if it is resolving the problem? You can also log the properties supposed to be read from the properties file to see what is loaded for them. – STaefi Feb 14 '20 at 11:30
  • Try changing the path to the property file to something like this @PropertySource("classpath:**/db/jdbc2.properties"). – lazy.coder Feb 14 '20 at 11:45
  • @STaefi I did same error. how can I do the logging you talked about? – usertest Feb 14 '20 at 12:10
  • @lazy.coder Failed to parse configuration class [com.apress.prospring5.ch6.config.AppConfig]; nested exception is java.io.FileNotFoundException: class path resource [**/db/jdbc2.properties] cannot be opened because it does not exist now it does not find the properties file. – usertest Feb 14 '20 at 12:10
  • This might help you https://stackoverflow.com/questions/20353402. It ideally says that your user can't access your db. Also if you are running in local system you can turn off useSSL=flase. – lazy.coder Feb 14 '20 at 12:29
  • @lazy.coder I can use prospring5/prospring5 to access the database from Workbench. and if Spring would have used those credentials the application would be able to work. useSSL=false didn't work either. – usertest Feb 14 '20 at 13:46
  • @STaefi . can you please see the edit. I have printed the loaded values and for some reason it takes 'Mehdi' instaed of 'prospring' – usertest Feb 14 '20 at 14:20
  • @STaefi . First I tried setting the values at initialization and that was no good. but after I used username = "prospring5"; dataSource.setUsername(username); it worked. so what does this mean. why Spring cannot load the username like it successfully loaded url and password. – usertest Feb 14 '20 at 14:35
  • Can you check if you have any environment variable named 'username'? try 'echo $username' in your terminal – lazy.coder Feb 14 '20 at 15:37
  • @lazy.coder I have fix it https://stackoverflow.com/a/60228628/4255756 Thanks – usertest Feb 14 '20 at 15:39

2 Answers2

0

Could you please try by giving a default value as :

@Value("${driverClassName:com.mysql.cj.jdbc.Driver}")
private String driverClassName;
@Value("${url:jdbc:mysql://localhost:3306/musicdb?useSSL=true}")
private String url;
@Value("${username:prospring5}")
private String username;
@Value("${password:prospring5}")
private String password;

And remove the @PropertySource("classpath:db/jdbc2.properties") at the top. If this works then you can try with the propertySource again

0

So I have fixed the problem by simply using a different String identifier in the .propreties file . I changed it to one=prospring5 and it worked. Apparently using a proprety named 'username' will be loaded with anything other than Your Computer name. I don't know if Spring provides a list of prohibited values for property names. if they don't, they certainly should consider.

usertest
  • 2,140
  • 4
  • 32
  • 51
  • 1
    Prohibited is a bit strong; you ran into a case of using a very ambiguous property name that happened to already be set by a Spring component. that's why it is advisable to use context-driven property names, like 'musicdb.username'. – Gimby Feb 14 '20 at 15:24
  • how about reserved? I know MySQL have a lot of them https://dev.mysql.com/doc/refman/8.0/en/keywords.html . Plus I did not came up with the name it is the book author of Pro Spring 5 that did. You check the source code for yourself. – usertest Feb 14 '20 at 15:29
  • The point I was making was to avoid ambiguous or generic names, I was not arguing terminology. This counts doubly for the names of beans you define yourself, by the way. I've been bitten by Spring upgrades at least three times now where I had to resolve duplicate bean names. This hurts a lot of the bean happens to be in a shared library used all over the place. – Gimby Feb 17 '20 at 08:43