Skip to content

Binding two Property classes and I need to merge them to one and Bind that too

I am working in a library which configures Property classes through Spring properties in an application.yml file.

I am moving from a deprecated prefix(com.myapp.deprecated) to a new prefix(com.myapp.newprefix). I want to maintain old applications that are already using the deprecated prefix for a short while to allow for a migration period. To achieve that I have made two classes that extend a class that contains the shared properties like so.

*note I use lombok so these would have @Data annotation on them.

public class BasePropertyClass {
    private String sharedProperty1;
    private String sharedProperty2;
}

@ConfigurationProperties("com.myapp.deprecated")
public class DeprecatedPropertyClass extends BasePropertyClass {

}

@ConfigurationProperties("com.myapp.newprefix")
public class newPropertyClass extends BasePropertyClass {
    private String newProperty;
}

now when I go to bind the property files, I am currently binding both the deprecated class and new class on a configuration class implementing EnvironmentAware.

@Configuration
public class ConfiguringClass implements EnvironmentAware {
    @Override
    public void setEnvironment(Environment environment) {
        
        DeprecatedPropertyClass deprecatedPropertyClass = Binder
            .get(environment)
            .bind("com.myapp.deprecated", DeprecatedPropertyClass.class)
            .orElse(null);

        newPropertyClass newPropertyClass = Binder
            .get(environment)
            .bind("com.myapp.newprefix", newPropertyClass.class)
            .orElse(null);
    }
}

My question is, I would like to take the DeprecatedPropertyClass and merge data from that class to newPropertyClass and then bind that to the context for other classes to use. However, implementing ApplicationContextAware happens too late and I don’t think I can use the Binder on an already instantiated object. I think I could use a BeanDefinitionBuilder but that would require me to redefine the object all over again and I would have multiple beans of the same type floating around. Is there a way to merge these two Properties classes together so I can use them as a single bean?

Answer

I think you can do this using org.springframework.beans.BeanUtils. It has copyProperties(T source, T target); i.e. used to copy the properties.

    public static void myCopyProperties(Object source, Object target) {
       BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
    }

getNullPropertyNames(src) is for ignoring null property.

    public static String[] getNullPropertyNames (Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<String>();
        for(java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) emptyNames.add(pd.getName());
        }

        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }