How to serialize a Map<String, String> using Simple XML? - java

How would you go about serialising a Map using simple XML so that it looks something like:
<elem foo="value">key</elem>
Instead of the normal
<elem foo="key">value</elem>
(The map is one to many, and since this will be edited by humans, I wanted it to be clearer.)
[EDIT]: Doesn't Fix.

Have you tried something like:
#ElementMap(entry="property", value="value", attribute=true, inline=true)
private Map<String, String> map;
or some combination, i.e. to use the other attributes of the #ElementMap annotation too?

Related

Creating a map in config files

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());
}

Best practice generating object for response

I have rest server with spring.
There is a lot of requests where one of the params is fields fields is the set of fields that server should return in response. like: /?fields=[id,name] and server should return JSON object with both fields
I would like to know what is the best practice for generating such response.
We do it like this:
private Map<String, Object> processBook(BookEntity book, Set<String> fields, String locale){
Map<String, Object> map = new HashMap<String, Object>();
//..
if(fields.contains(ID)){
map.put(ID, book.getId());
}
if(fields.contains(ISBN)){
map.put(ISBN, book.getIsbn());
}
if(fields.contains(DESCRIPTION)){
if(locale.equals(UserLocale.UK)) map.put(DESCRIPTION, book.getDescriptionUa());
else if(locale.equals(UserLocale.RU)) map.put(DESCRIPTION, book.getDescriptionRu());
else map.put(DESCRIPTION, book.getDescriptionEn());
}
//..
return map;
}
Maybe there is much better alternative?
Note that in your case you obtain all data from DB - fully filled BookEntity object, and then show only requested fields.
In my opinion it'd be "much better alternative" to delegate field list to appropriate downstream integration call and get BookEntity object only with necessary fields. Then mentioned above method will reduce to just one line, your DB responses will be more lightweight, so it will bring simplicity and optimization gain to your system.
Any adequate DB provides such functionality: SQL or NoSQL, etc.
P.S. Plus standard approach of Object to JSON mapping such as Jackson or GSON at top level.
Instead of having a Map, you could have and object with the attributes you need and set them, instead of adding to map.Then you can use Google's Gson to transform your object into a Json object.Take a look at this quick tutorial.
One approach is to have an asMap function.
Map<String, Object> map = book.asMap();
map.keySet().retainAll(fields);

Java YAML Configuration to a custom hashmap

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!

Flattening of json to a map with Jackson

I am currently using the Jackson library to unmarshal json to pojos, using annotations.
The json tree that I would like to unmarshal is as follows:
{
"key1":"value1",
"key2":"value2",
"key3":{
"key31":{
"key311":"value311",
"key312":"value312",
"key313":"value313"
},
"key32":"value32"
},
"key4":"value4",
"key5":"value5",
"key6":{
"key61":"value61"
}
}
I don't know the json structure in advance and would like to completely flatten it to a Map which content would be equivalent to:
Map<String, Object> outputMap = new HashMap<String, Object>();
outputMap.put("key1", "value1");
outputMap.put("key2", "value2");
outputMap.put("key311", "value311");
outputMap.put("key312", "value312");
outputMap.put("key313", "value313");
outputMap.put("key32", "value32");
outputMap.put("key4", "value4");
outputMap.put("key5", "value5");
outputMap.put("key61", "value61");
(note that keys "key3", "key31" and "key6" should be ignored)
Using the annotation #JsonAnySetter, I can create a function to populate the map with all top level atoms, but the method will also catch the node having children (when the value is a Map).
From that point, I can of course write myself the simple recursion over the children, but I would like this part to be handled automatically (in an elegant way) through the use of a facility from the library (annotation, configuration, etc.), and not have to write the recursion by myself.
Note: we assume there is not name clashing in the different level keys.
There is no annotation-based mechanism to do this that I know of, since #JsonUnwrapped which might be applicable is only usable with POJOs, not Maps.
I guess you could file an enhancement request to ask #JsonUnwrapped to be extended to also handle Map case, although it seems only appicable for serialization (not sure how one could deserialize back).

Access Map<Enum, Object> in JSTL

I have:
public enum MyEnum{
One, Two, Three
}
From controller, I put in the model:
HashMap<MyEnum, Long> map = new HashMap<MyEnum, Long>();
map.put(MyEnum.One, 1L);
mav.addObject( "map", map);
How do I in my JSTL access the object in the map for key enum MyEnum.One, in a neat way?
${map['One']} //does not seem to work...
nor does
${map[MyEnum.One]}
It's not exactly true that you can't do it, but the solution isn't completely straight forward. The issue is EL is not converting the string you pass in as the map key to the corresponding enum for you, so putting ${map['One']} does not use the enum constant MyEnum.One in the map lookup.
I ran into the same issue and didn't want to revert to going with a String keyed map, so the challenge then was in JSTL how to get the actual enum reference to use in the map lookup.
What is required is to get the Enum constants into the scope of the JSP so that you can then use the actual Enum itself as the key. To do this, in the controller you do something like this:
for (MyEnum e : MyEnum.values()) {
request.putAttribute(e.toString(), e);
}
What you've done here is added variables into the scope named as the string representation of the enum. (you could of course avoid naming issues by prepending the e.toSring() with some value)
Now, when you do the following
${map[ONE]}
You will be using the actual enum constant as the key and will therefore get back the proper corresponding value from the map. (notice there are no quotes around ONE, that is because you are referencing the request attribute ONE in this case, that was added above)
You can't. Your best bet is to change your map to use enum.name() as key:
HashMap<String, Long> map = new HashMap<String, Long>();
map.put(MyEnum.One.name, 1L);
map.addObject( "map", map);
Your first approach would work then:
${map['One']} // works now
Or you can write a custom EL function to do the above for you if you can't / don't want to change the map.
I usually use this solution:
<%#page import="my.package.MyEnum"%>
<c:set var="One" value="<%=MyEnum.One %>" />
<c:set var="MyEnum_values" value="${map[One]}" />
First, I import the enum. Then, I save the enum value I want into JSTL variable. Then I can access the map with this variable as the key.
${map[MyEnum.One]}
It works for me. But you have to write the complete name of your class: my.package.MyEnum or to import MyEnum class:
<%#page import="my.package.MyEnum"%>

Categories