We have one application where we use configuration files and they have fields as arrays and normal variables:
metadata {
array=["val1", "val2"]
singleValue=2.0
}
Now, I know how to extract these above values like
config.getStringList("metadata.array").asScala.toArray
and config.getString("metadata.singleValue)
But, is there any way I can define maps here so that I can find value wrt desired key from that map.
This config is an object of
public interface Config extends com.typesafe.config.ConfigMergeable
You can use config.getConfig("metadata") to obtain a (sub)config object.
Converting the (sub)config to a map is something you'll have to do yourself. I would use config.entrySet() to obtain the entries as key-values, and load it into a map that way.
I haven't tried compiling/testing this code, but something like this should work:
Map<String,Object> metadata = new HashMap<>();
for (Map.Entry<String,ConfigValue> entry : config.entrySet()) {
metadata.put(entry.getKey(), entry.getValue().unwrapped());
}
Related
I have a code that consumes map of properties with string keys which represents some kind of context. And I want this code to fail if the map does not contain some of the required properties.
The corresponding code might look like this:
SomeResultType businessMethod(Map<String, String> context) {
Assert.isTrue(context.containsKey("A"), "A property must not be empty");
Assert.isTrue(context.containsKey("B"), "B property must not be empty");
Assert.isTrue(context.containsKey("C"), "C property must not be empty");
// ...
}
I wrote a simple replacement by myself with signature like this
public static <K, V> void mapContainsKeys(Map<K, V> map, K... keys)
But I think that something like this must be already implemented somewhere. So I'm searching for library replacement of this code.
It would be great if Spring guys implemented something like this in org.springframework.util.Assert.
if you want to just check that a map contains a list of keys, use this:
map.keySet().containsAll(keys)
if you want more details, to know which ones were missing:
Set<String> missingKeys = new HashSet<>(keys);
missingKeys.removeAll(map.keySet());
and then:
if (!missingKeys.isEmpty()) {
throw new IllegalArgumentException(missingKeys + " keys missing");
}
The fact that you had to write a helper method means that you are probably manipulating maps all over your code.
Looks like a code smell to me, you should probably map your properties to an object that you can validate once and pass everywhere.
Since you are using Spring, and if you are using Spring Boot (most people do nowadays), you can use #ConfigurationProperties to map your configuration properties to an object.
This way you can also add validation like #javax.validation.constraints.NotNull and make sure your properties are valid.
Using yaml in my Spring-boot application (with snakeyaml dependency 1.16) I am attempting to create a #ConfigurationProperties based off of my application.yml file. I want to create a data structure like the json below which is a Map with String Keys and Array values.
mapName: {
"key1": ["elem0","elem1"],
"key2": ["hello","world"]
}
Attempting to create a Spring configuration class as follows
#Component
#ConfigurationProperties(prefix = "channel-broker")
#EnableConfigurationProperties
public class BrokerConfiguration {
private Map<String, Set<String>> broker = new HashMap<>();
public Map<String, Set<String>> getBroker() {
return broker;
}
}
I have tried the following for my yaml
channel-broker:
broker: {message-delivery: ['all'], facebook: ['client1']}
Attempt two
channel-broker:
message-delivery: ['all']
facebook: ['client1']
Attempt three
channel-broker:
message-delivery:
- ['all']
facebook:
- ['client1']
I have also tried initializing the HashMap in the #ConfigurationProperties class as such ... new HashMap<String, Set<String>> this didn't work either
All attempts result in this error which makes me believe its an error when converting to the object not that there is anything wrong with the yaml syntax.
Caused by: org.springframework.beans.InvalidPropertyException: Invalid
property 'brokerTest[message-delivery][0]' of bean class
[my.classpackage.clasname]:
Property referenced in indexed property path
'brokerTest[message-delivery][0]' is neither an array nor a List nor a
Map; returned value was [all]
Is it possible to create such an object? How would I accomplish this
-UPDATE-
If I change the Set to an ArrayList (or List interface) this works but that isn't what I'm looking for. changed to this
private Map<String, ArrayList<String>> brokerTest = new HashMap<>();
but need this doesn't work with Set interface either:
private Map<String, HashSet<String>> brokerTest = new HashMap<>();
This issue was being caused by the format of the yaml file. The following structure allowed me to build my graph like data structure out of yaml
channel-broker:
broker:
message-delivery:
all
facebook:
client1,client2
The Set doesn't want anything extra surrounding the key. Note if your Set will contain multiple values you can add a comma to separate them. Just like Json the last element will not have a comma after.
What you are looking for is this :
channel-broker: {broker: {message-delivery:['all', ...], facebook:['client1', ...]}}
see Complete idiot's introduction to yaml
If you use [] then it's an array so arraylist works, for hashset/hashmap you need to use {} brackets.
channel-broker: {
broker: {
message-delivery:{'all', '123'},
facebook:{'client1', 'cleant2'}
}
}
will work for hashset.
(hashmap example)
I have to develop one desktop base application(it has no request/response) and it has many classes.
my Main/Controller class read (*.properties) file,
like
allExtensions = properties.getProperty("ReportFileExtension");
and i have mention some file extension in .properties file like ReportFileExtensionn = .pdf,.doc etc.
This key read from .properties file in Main class and i want use this key value in other class without passing argument in any method or constructor.
is it spring provide a local storage ? so i can use to store attribute and use it other class.
Thanks in Advc.
Your question is bit confusing but based on comments I think you are struggling to understand how to get keys from properties.
Check PropertiesLoaderUtils
Resource resource = new ClassPathResource("/my.properties");
Properties props = PropertiesLoaderUtils.loadProperties(resource);
Now iterate over the props object
Try this
public Set<Object> getAllKeys(){
Set<Object> keys = prop.keySet();
return keys;
}
Or this
public void printProperties() {
for(Entry<Object, Object> e : props.entrySet()) {
System.out.println(e);
}
}
Properties are available globally but if you want you can create a static map and cache the properties in it.
I am currently programming a bukkit plugin that stores a bunch of information about the player in a YAML configuration file. Now I want the plugin to read the YAML file when the server starts up and then add on the that information. I have my loader, but I cant use it because my plugin uses a custom map. Here is the code for the map:
Map<Integer, Map<String, Object>>
And here is the code to get the information from the file:
info = (Map<Integer, Map<String, Object>>) ticket.getConfigurationSection("tickets");
But when I try to run the plugin with that line of code i get this error:
Caused by: java.lang.ClassCastException: org.bukkit.configuration.MemorySection cannot be cast to java.util.Map
Full code is posted here: http://pastebin.com/Xgu8hwM0
The solution to this is not using a custom map. You already get a MemorySection from your configuration.
Work with that. Instead of casting you should use the method: getValues(boolean) which returns a Map<String, Object> containing all the relevant information and is specified by the Interface ConfigurationSection.
ticket.getConfigurationSection("tickets").getValues();
See also the relevant excerpt at bukkit's Configuration API Reference:
The getValues method will return the values in the
ConfigurationSection as a map, it takes a boolean which controls if
the nested maps will be returned in the map.
Yes I solved this. I HAD to use the Map<String, Object> but it worked because the way I had it(Map<Integer, Map<String, Object>>) that is the second part!
I have a class which has a Map as its member variable. Something like this -
public Clas Engine{
private Map<String,List<String>> filesByKey;
public void setFilesByKey(Map<String,List<String>> map) {
this.filesByKey = map;
}
public Map<String,List<String>> getFilesByKey() {
return filesByKey;
}
}
User can specify any number of keys in the map and its not predefined concept. They can basically group any number of files into one key and provider the map Value.
I was using PropertyOverrideConfigurer and in the properties file, I was trying to do something like this -
engine.filesByKey[key1][0]=file1
engine.filesByKey[key1][1]=file2
engine.filesByKey[key2][0]=anotherfile1
engine.filesByKey[key2][1]=anotherfile2
Now this is not working because the the List value corresponding to key1 or key2 is null to being with. So Spring Bean creation fails with the message that it can not set value to a property which is NULL.
What is the best way to handle this situation?
You should be able to use the LazyMap & LazyList from commons collections to achieve this.
Try to initialize your filesByKey variable with DefaultedMap from commons collections. It can return default value instead of null if map doesn't contain required key.