0

I develop Spring-Mvc project and this project's application properties count too much. Also I can't change this properties during program is running. So, I want to get this properties from database and assign to member of classes.

Now, I take this properties from database by using a service but I don't think, this code is reusable. I wonder, is there any methodology to get this properties to members via custom annotation?

ApplicationPropertiesDao.java

@Repository
public class ApplicationPropertiesDao implements IApplicationPropertiesDao{
    @Value("#{appProperties.instanceName}")
    private String instanceName;

    @Override
    @Cacheable("applicationProperties")
    public HashMap<String, String> getApplicationPropertiesFromDB(){
        Map<String, Object> inputMap = new HashMap<String, Object>();
        inputMap.put("instanceName", instanceName);

        String sql = getSQL("getApplicationProperties");
        Map<String, String> list = new HashMap<String, String>();

        getNamedParameterJdbcTemplate().query(sql, inputMap, new ResultSetExtractor<Map<String, String>>() {
            @Override
            public Map<String, String> extractData(ResultSet resultSet) throws SQLException, DataAccessException {
                while (resultSet.next()) {
                    list.put( resultSet.getString("NAME"),resultSet.getString("VALUE"));
                }
                return list;
            }
        });
        return (HashMap<String, String>) list;
    }
}

ApplicationPropertiesService.java

@Service
public class ApplicationPropertiesService implements IApplicationPropertiesService{
    @Autowired
    private IApplicationPropertiesDao applicationPropertiesDao;

    public HashMap<String, String> getApplicationPropertiesFromDB(){
        return applicationPropertiesDao.getApplicationPropertiesFromDB();
    }

    public Object getApplicationPropertyByName(String name, ApplicationPropertyValueTypeEnum applicationPropertyValueTypeEnum){
        String value = getApplicationPropertiesFromDB().get(name);

        if (applicationPropertyValueTypeEnum.name().equals(ApplicationPropertyValueTypeEnum.INTEGER.toString())){
            return Integer.parseInt(value);
        }else if(applicationPropertyValueTypeEnum.name().equals(ApplicationPropertyValueTypeEnum.BOOLEAN.toString())){
            String upperCaseValue = value.toUpperCase(Locale.ENGLISH);
            return upperCaseValue.equals("TRUE") ? Boolean.TRUE : Boolean.FALSE;
        }
        return value;
    }
}

Can I create a custom annotation as shown below for this situation? If there is , I will be happy. How can i make this?

@Service
public class Demo{
    private String val;
    @Autowired
    public ApplicationPropertiesService applicationPropertiesService;

    @GetPropertyFromDB(key = "val", type = "String")
    public getVal(){
        //set(applicationPropertiesService.getApplicationPropertyByName("val", "String"));
        return this.val;
    }

    public void setVal(String val){
         this.val = val;
    }
}

Thank you for your help.

S.Balaban
  • 174
  • 2
  • 19

2 Answers2

1

I think you need DB PropertyPlaceholderConfigurer. Something like this: Spring PropertyPlaceholderConfigurer load from DB

If you integrate your custom DB PropertyPlaceholderConfigurer. (see https://www.baeldung.com/properties-with-spring)

@Bean
public static PropertySourcesPlaceholderConfigurer properties(){
    return new MyDBPlaceholderConfigurer();
}

You will be able to use standard @Value and @ConfigurationProperties annotations.

i.bondarenko
  • 3,442
  • 3
  • 11
  • 21
0

I used this class to configuration of properties at start but I could not load this properties from database at specific time periods. This class works only start. Can I call this loadProperties method for every minute without restarting the program?

DbPropertyPlaceholderConfigurer.java

@Service
public class DbPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
private DataSource dataSource;
private String key = "NAME";
private String value = "VALUE";
private String table = "APPLICATION_PROPERTIES";
private String instanceName;


@Override
protected void loadProperties(final Properties props) throws IOException {
    if (null == props) {
        throw new IOException("No properties passed by Spring framework - cannot proceed.");
    }

    String sql = String.format("SELECT %s, %s FROM %s where INSTANCE_NAME = '%s'", key, value,
            table, instanceName);

    try {
        JdbcTemplate t = new JdbcTemplate(dataSource);
        t.query(sql, new RowCallbackHandler() {
            @Override
            public void processRow(ResultSet rs) throws SQLException {
                String auxKey = rs.getString(key);
                String auxValue = rs.getString(value);

                if (null == auxKey || null == auxValue) {
                    throw new SQLException("Configuration database contains empty data. Name='" + (auxKey == null ? "" : auxKey)
                            + "', Value='" + (auxValue == null ? "" : auxValue) + "'.");
                }

                props.setProperty(auxKey, auxValue);
            }
        });
    } catch (Exception e) {
        logger.error("There is an error in the configuration database.");
        throw new IOException(e);
    }

    if (props.size() == 0) {
        logger.error("The configuration database could not be reached or does not contain any properties in '" + table
                + "'.");
    } else {
        logger.info("Application config info loaded from configuration database.");
    }
}

public void setDataSource(DataSource dataSource) {
    this.dataSource = dataSource;
}

public void setInstanceName(String instanceName) {
    this.instanceName = instanceName;
}

}

applicationContext.xml

<bean id="placeholderPropertiesDatabase" class="com.common.DbPropertyPlaceholderConfigurer" >
    <property name="dataSource" ref="dataSource" />
    <property name="instanceName" value="instance1" />

    <property name="placeholderPrefix" value="$db{" />
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
    <property name="ignoreUnresolvablePlaceholders" value="false" />
    <property name="order" value="1" />
</bean>
S.Balaban
  • 174
  • 2
  • 19