Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Working with properties in Spring to make a list of objects

I'm working with properties in Spring and I have a doubt about the Properties

Valores.properties

estudiante.nombre=Antonio, Juan , Maria, Raquel
estudiante.edad=28,20,21,23

Now I have a class to develop the bean

public class Estudiante {

    public Estudiante() {
    }

    public Estudiante(String nombre, Integer edad) {
        super();
        this.nombre = nombre;
        this.edad = edad;
    }

    @Value("${estudiante.nombre}")
    private String nombre;

    @Value("${estudiante.edad}")  
    private Integer edad;

    public Integer getEdad() {      
        return edad;
    }

    public void setEdad(Integer edad) {     
        this.edad = edad;
    }

    public String getNombre() {     
        return nombre;
    }

    public void setNombre(String nombre) {  
        this.nombre = nombre;
    }

    @Override
    public String toString() {
        return '\n' +"Estudiante{" + "nombre=" + nombre + ", edad=" + edad + '}';
    }

}

A java class to make the configuration

@Configuration
@PropertySource(value="classpath:valores.properties")
public class AppConfig {

    @Value("#{'${estudiante.nombre}'.split(',')}")
    private List<String> nombres;
    @Value("#{'${estudiante.edad}'.split(',')}")    
    private List<Integer> edades;

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

    public List<String> getNombres() {
        return nombres;
    }


    public List<Integer> getEdades() {
        return edades;
    }

    public List<Estudiante> getListaStudents() {

        List<Estudiante> listaStudents = new ArrayList<>();

        for (int i= 0;i< nombres.size();i++){
            listaStudents.add(new Estudiante(nombres.get(i),edades.get(i)));
        }

        return listaStudents;
    }

}

And the main java class

public class Principal {

    public static void main(String[] args) {

        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        AppConfig appConfig = context.getBean(AppConfig.class);
        System.out.println(appConfig.getListaStudents());
        ((ConfigurableApplicationContext)context).close();
    }

}

The program works and the output is OK

[
Estudiante{nombre=Antonio, edad=28}, 
Estudiante{nombre= Juan , edad=20}, 
Estudiante{nombre= Maria, edad=21}, 
Estudiante{nombre= Raquel, edad=23}]

But I don't know if it is the right way to develop. I dón't like to build a method getListaStudents() in the AppConfig class to make a list of objets and I don't like to use the new() method in Spring

I think it's not a good idea but I don't know other way to solve. Any solution or any idea?

Thanks in advance

like image 518
Antonio Avatar asked Oct 31 '22 06:10

Antonio


1 Answers

I think this is a proper approach with few improvements, but depending on the data size and requirements you may not want to load data from property files. Property files are usually used for configuration options such as database configurations for different environments, caching configurations etc..

In your AppConfig, you don't need to use SpringEL to parse a List of Integers or Strings like this,

@Value("#{'${estudiante.nombre}'.split(',')}")
private List<String> nombres;

I would suggest to use something like this instead,

@Value("${estudiante.edad}") List<Integer> nombres

but for this to work you need to have one addtional bean configuration for Spring's ConversionService

@Bean
public ConversionService conversionService() {
    return new DefaultConversionService();
}

This way Spring's conversion service will have default converters to convert a list of Strings or Integers so that you can avoid somewhat less readable #{'${estudiante.edad}'.split(',')} in @Value annotation.

Now you can use above @Value to be used directly in a new bean to create a set of Students like this.

@Bean
public List<Estudiante> getStudents(
        @Value("${estudiante.edad}") List<Integer> numbers,
        @Value("${estudiante.nombre}") List<String> names) {

    List<Estudiante> listaStudents = new ArrayList<Estudiante>();
    for (int i= 0;i< numbers.size();i++){
        listaStudents.add(new Estudiante(names.get(i), numbers.get(i)));
    }

    return listaStudents;
}

and you can inject list of Estudiantes with @Resource,

@Resource(name = "getStudents")
private List<Estudiante> estudiantes;

I don't see anything wrong with creating Estudiante objects with new keyword. Just as we use new in other methods that are annotated with @Bean this is a perfectly valid scenario. If you want, for whatever reason to avoid new in creating Estudiante, you can inject ApplicationContext and get Estudiante with Estudiante studiante = applicationContext.getBean(Estudiante.class); and don' forget to mark Estudiante class with @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

I dón't like to build a method getListaStudents() in the AppConfig class to make a list of objects

As far as I know there is no simple and proper way to create a List of Estudiante objects as they need to have their own values. You can make student creation to its own configuration class such as EstudianteConfiguration and import it to your main AppConfig class with @Import annotation.

like image 64
Bunti Avatar answered Nov 09 '22 23:11

Bunti