java - not - propertysourcesplaceholderconfigurer
Cómo rellenar HashMap desde el archivo de propiedades de Java con Spring @Value (4)
¿Es posible usar Spring @Value para mapear valores del archivo de propiedades al HashMap?
Sí lo es. Con un poco de ayuda de código y Spel .
En primer lugar, considere este singleton Spring-bean (debe escanearlo):
@Component("PropertySplitter")
public class PropertySplitter {
/**
* Example: one.example.property = KEY1:VALUE1,KEY2:VALUE2
*/
public Map<String, String> map(String property) {
return this.map(property, ",");
}
/**
* Example: one.example.property = KEY1:VALUE1.1,VALUE1.2;KEY2:VALUE2.1,VALUE2.2
*/
public Map<String, List<String>> mapOfList(String property) {
Map<String, String> map = this.map(property, ";");
Map<String, List<String>> mapOfList = new HashMap<>();
for (Entry<String, String> entry : map.entrySet()) {
mapOfList.put(entry.getKey(), this.list(entry.getValue()));
}
return mapOfList;
}
/**
* Example: one.example.property = VALUE1,VALUE2,VALUE3,VALUE4
*/
public List<String> list(String property) {
return this.list(property, ",");
}
/**
* Example: one.example.property = VALUE1.1,VALUE1.2;VALUE2.1,VALUE2.2
*/
public List<List<String>> groupedList(String property) {
List<String> unGroupedList = this.list(property, ";");
List<List<String>> groupedList = new ArrayList<>();
for (String group : unGroupedList) {
groupedList.add(this.list(group));
}
return groupedList;
}
private List<String> list(String property, String splitter) {
return Splitter.on(splitter).omitEmptyStrings().trimResults().splitToList(property);
}
private Map<String, String> map(String property, String splitter) {
return Splitter.on(splitter).omitEmptyStrings().trimResults().withKeyValueSeparator(":").split(property);
}
}
Nota: PropertySplitter
clase PropertySplitter
usa la utilidad Splitter
de Guava. Por favor, consulte su documentación para más detalles.
Entonces, en un frijol tuyo:
@Component
public class MyBean {
@Value("#{PropertySplitter.map(''${service.expiration}'')}")
Map<String, String> propertyAsMap;
}
Y finalmente, la propiedad:
service.expiration = name1:100,name2:20
No es exactamente lo que ha preguntado, porque este PropertySplitter
funciona con una sola propiedad que se transforma en un Map
, pero creo que podría cambiar a esta manera de especificar propiedades o modificar el código PropertySplitter
para que coincida con el más jerárquico camino que deseas.
¿Es posible utilizar Spring @Value para mapear valores del archivo de propiedades al HashMap?
Actualmente tengo algo como esto, y mapear un valor no es un problema. Pero necesito asignar valores personalizados en expiraciones de HashMap. Es algo como esto posible?
@Service
@PropertySource(value = "classpath:my_service.properties")
public class SomeServiceImpl implements SomeService {
@Value("#{conf[''service.cache'']}")
private final boolean useCache = false;
@Value("#{conf[''service.expiration.[<custom name>]'']}")
private final HashMap<String, String> expirations = new HashMap<String, String>();
Archivo de propiedad: ''my_service.properties''
service.cache=true
service.expiration.name1=100
service.expiration.name2=20
¿Es posible mapear como esta clave: conjunto de valores
name1 = 100
name2 = 20
Desde Spring 4.1.x (aunque no recuerdo la versión específica), puedes hacer algo como
@Value("#{${your.properties.key.name}}")
private Map<String, String> myMap;
donde your.properties.key.name en su archivo de propiedades debería ser algo así como
your.properties.key.name={/
name1 : 100, /
name2 : 200 /
}
Solo asegúrese de crear el bean PropertySourcesPlaceholderConfigurer para que funcione tanto en su aplicación como si está escribiendo un código de prueba unitaria para probar el código; de lo contrario, $ {...} marcador de posición para el valor de la propiedad no funcionará como se espera y verás algunos errores SpringEL extraños.
Hago una solución inspirada en la publicación anterior.
Registrar el archivo de propiedad en la configuración de Spring:
<util:properties id="myProp" location="classpath:my.properties"/>
Y creo componentes:
@Component("PropertyMapper")
public class PropertyMapper {
@Autowired
ApplicationContext applicationContext;
public HashMap<String, Object> startWith(String qualifier, String startWith) {
return startWith(qualifier, startWith, false);
}
public HashMap<String, Object> startWith(String qualifier, String startWith, boolean removeStartWith) {
HashMap<String, Object> result = new HashMap<String, Object>();
Object obj = applicationContext.getBean(qualifier);
if (obj instanceof Properties) {
Properties mobileProperties = (Properties)obj;
if (mobileProperties != null) {
for (Entry<Object, Object> e : mobileProperties.entrySet()) {
Object oKey = e.getKey();
if (oKey instanceof String) {
String key = (String)oKey;
if (((String) oKey).startsWith(startWith)) {
if (removeStartWith)
key = key.substring(startWith.length());
result.put(key, e.getValue());
}
}
}
}
}
return result;
}
}
Y cuando quiero mapear todas las propiedades que comienzan con el valor de specifix en HashMap, con la anotación @Value:
@Service
public class MyServiceImpl implements MyService {
@Value("#{PropertyMapper.startWith(''myProp'', ''service.expiration.'', true)}")
private HashMap<String, Object> portalExpirations;
La solución más rápida basada en Spring Boot que se me ocurre es la siguiente. En mi ejemplo particular estoy migrando datos de un sistema a otro. Es por eso que necesito un mapeo para un campo llamado prioridad .
Primero he creado el archivo de propiedades (priority-migration.properties) como este:
my.prefix.priority.0:0
my.prefix.priority.10:1
my.prefix.priority.15:2
my.prefix.priority.20:2
another.prefix.foo:bar
y ponerlo en el classpath.
Suponiendo que desea utilizar el mapa en un bean / componente manejado por resorte, anote su clase con:
@Component
@PropertySource("classpath:/priority-migration.properties")
Lo que realmente quiere en su mapa es, por supuesto, solo los pares clave / valor que están prefijados con my.prefix, es decir, esta parte:
{
0:0
10:1
15:2
20:2
}
Para lograr eso, debe anotar su componente con
@ConfigurationProperties("my.prefix")
y crea un getter para el infijo prioritario . Este último resultó ser obligatorio en mi caso (aunque el documento de Sring dice que es suficiente tener una prioridad de propiedad e inicializarlo con un valor variable)
private final Map<Integer, Integer> priorityMap = new HashMap<>();
public Map<Integer, Integer> getPriority() {
return priorityMap;
}
En el final
Se ve algo como esto:
@Component
@ConfigurationProperties("my.prefix")
@PropertySource("classpath:/priority-migration.properties")
class PriorityProcessor {
private final Map<Integer, Integer> priorityMap = new HashMap<>();
public Map<Integer, Integer> getPriority() {
return priorityMap;
}
public void process() {
Integer myPriority = priorityMap.get(10)
// use it here
}
}