In a REST controller in Spring boot, I am trying to iterate the values in a RequestBody response and put some of them in a HashMap in a POST endpoint.
The JSON I am sending is of this structure:
{"name":"yogurt","vitaminA":6,"vitaminb12":5}
The endpoint looks like this so far:
#RequestMapping("/create")
public NutrientList createNUtrientList(#RequestBody NutrientList nutrientList) {
Map<String, Double> nutrientMap = new HashMap<String,Double>();
//get nutrient values, need help with this part
for()
//add values to map
NutrientList nl = new NutrientList(nutrientList.getName(), nutrientMap);
//will save to repository
return nl;
}
The NutrientList class looks like this:
public class NutrientList {
#Id
private ObjectId id;
#JsonProperty("name")
private String name;
#JsonProperty("nutrientMap")
Map <String,Double> nutrientMap = new HashMap<String,Double>();
public NutrientList() {}
public NutrientList(String name, Map<String, Double> nutrientMap) {
this.id = new ObjectId();
this.name = name;
this.nutrientMap = nutrientMap;
}
//setters and getters
}
The data is stored by separate nutrient in the database, it is not a map. I see the NutrientList class does not share the same structure, but is there any way I can get around this to be able to use a map without changing how it is stored in the database?
I need to use a map because there are many nutrients and I don't want to have separate variables for them. Thank you so much. Let me know if something is not clear.
EDIT:
I could alternately turn the csv where I got the data in the database from into JSON format with the map, but I have not found a tool online that gives me this flexibility.
If you have a list of valid keys, you could use the following:
private static final List<String> validKeys = Arrays.asList("vitaminA", "vitaminB" /* ... */);
#RequestMapping("/create")
public NutrientList createNutrientList(#RequestBody Map<String, Object> requestBody) {
Map<String, Double> nutrientMap = new HashMap<>();
for (String nutrient : requestBody.keySet()) {
if (validKeys.contains(nutrient) && requestBody.get(nutrient) instanceof Number) {
Number number = (Number) requestBody.get(nutrient);
nutrientMap.put(nutrient, number.doubleValue());
}
}
String name = (String) requestBody.get("name"); // maybe check if name exists and is really a string
return new NutrientList(name, nutrientMap);
}
If you want to use Java 8 Stream API you can try:
private static final List<String> validKeys = Arrays.asList("vitaminA", "vitaminB" /* ... */);
#RequestMapping("/create")
public NutrientList createNutrientList(#RequestBody Map<String, Object> requestBody) {
Map<String, Double> nutrientMap = requestBody.entrySet().stream()
.filter(e -> validKeys.contains(e.getKey()))
.filter(e -> e.getValue() instanceof Number)
.collect(Collectors.toMap(Map.Entry::getKey, e -> ((Number) e.getValue()).doubleValue()));
String name = Optional.ofNullable(requestBody.get("name"))
.filter(n -> n instanceof String)
.map(n -> (String) n)
.orElseThrow(IllegalArgumentException::new);
return new NutrientList(name, nutrientMap);
}
Hope that helps.
Related
I would like to read from an unstructured CSV file. It means it will have different columns types every time. Please help.
Yes, Finally Myself found the solution and i would like to share with you. You can write a LineMapper and you can map unstructured header (dynamic- columns) with each line by the following code. Please Note i have read header while job scheduling and pass it as JobParameter.
#Bean
#StepScope
public FlatFileItemReader<Customer> csvReader(#Value("#{jobParameters[filepath]}") String filepath,
#Value("#{jobParameters[header]}") String header,
#Value("#{jobParameters[campaignId]}") String campaignId,
#Value("#{jobParameters[_id]}") String _id) {
FlatFileItemReader<Customer> flatFileItemReader = new FlatFileItemReader<>();
flatFileItemReader.setResource(new FileSystemResource(filepath));
flatFileItemReader.setName("customer-csv-file-reader");
flatFileItemReader.setLinesToSkip(1);
flatFileItemReader.setLineMapper(lineMapper(header,campaignId,_id));
return flatFileItemReader;
}
#Bean
#StepScope
public LineMapper<Customer> lineMapper(#Value("#{jobParameters[header]}") String header,
#Value("#{jobParameters[campaignId]}") String campaignId,
#Value("#{jobParameters[_id]}") String _id) {
return new LineMapper<Customer>() {
public String[] headers = header.split(",");
#Override
public Customer mapLine(String line, int linenumber) throws Exception {
Customer item = new Customer();
String[] p = line.split(",");
Map<String, String> properties = IntStream.range(0, headers.length).boxed()
.collect(Collectors.toMap(i -> headers[i], i -> p[i]));
item.setCampaignId(new ObjectId(campaignId));
item.setInviteId(new ObjectId(_id));
item.setProperties(properties);
return item;
}
};
}
I am trying to put String "0" in the parameter but in the table i`m getting 1 in the specified column.
in php script i have this code: (i removed the irrelevant code)
$isRegistered= $_POST['isRegistered'];
$sql = "INSERT INTO Users (isRegistered) VALUES ('$isRegistered')";
in my java code i have: (i removed the irrelevant code)
private static final String USER_IS_REGISTERED = "isRegistered";
private static final String FALSE = "0";
StringRequest stringRequest = new StringRequest(Request.Method.POST, URL_LINK,
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put(USER_IS_REGISTERED,FALSE);
return params;
}
};
Is there a way to serialize an object so that it could then be rehydrated by .Net Core Configuration Binder?
Basically, I'd like to get this Test to pass:
[Test]
public void Can_Serialize_And_Rehydrate()
{
var foo = new Foo{ Prop1 = 42; Prop2 = "Test" }
Dictionary<string, string> serialized = Serialize(Foo);
var deserializedFoo = new Foo();
new ConfigurationBuilder()
.AddInMemoryCollection(serialized)
.Build()
.Bind(deserializedFoo);
Assert.AreEqual(deserializedFoo.Prop1, 42);
Assert.AreEqual(deserializedFoo.Prop2, "Test");
}
Is there a Serializer out-of-the-box, or am I'm going to need to write my own Serialize() method?
AddInMemoryCollection's signature is like below, so why are you trying to serialize your dictionary here? You could just use it as it is.
public static IConfigurationBuilder AddInMemoryCollection(
this IConfigurationBuilder configurationBuilder,
IEnumerable<KeyValuePair<string, string>> initialData)
If you like to know more about how to test your custom configurations, I would suggest to look here:
https://github.com/aspnet/Configuration/blob/1.0.0/test/Microsoft.Extensions.Configuration.Binder.Test/ConfigurationBinderTests.cs
I was able to get this working by "hijacking" a JsonConfigurationProvider and plugging serialized Json directly into it. Not sure if this is the best way, but it does work:
public class ConfigurationSerializer
{
private class CustomJsonProvider : JsonConfigurationProvider
{
public CustomJsonProvider() : base(new JsonConfigurationSource())
{
}
public IDictionary<string, string> GetData(Stream s)
{
Load(s);
// Return the Configuration Dictionary
return Data;
}
}
public Dictionary<string, string> Serialize(object o)
{
var serialized =
JsonConvert.SerializeObject(
o,
new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(serialized)))
{
var jsonProvider = new CustomJsonProvider();
return jsonProvider
.GetData(ms)
.ToDictionary(key => key.Key, value => value.Value);
}
}
}
I want to print HashMultiMap as json.
HashMultimap<String,Object> multimap = HashMultimap.create();
multimap.put("a",Obj1);
multimap.put("a",Obj3);
multimap.put("b",Obj2);
to
{
"a":[Obj1,Obj3],
"b":[Obj2]
}
Obj1 and other objects should again be in json(to keep it clean, I have shown it as objects)
I can iterate over the individual keys and convert set of Objects to json using libraries such as Gson.
But to get the entire snapshot of the HashMultimap, I want to convert it to json and inspect it.
Gson could not convert the entire map, but could do individual values(list of objects to json)
Call asMap() on the MultiMap first. This converts the MultiMap to a standard Map where each value is a Collection.
In your example, the type of the resulting Map is Map<String, Collection<Object>>. Gson should be able to serialise this correctly.
You need to write a JsonAdapter or both JsonDeserializer and JsonSerializer. It's rather terrible, but I wanted to try.
Basically, you delegate everything to a Map<String, Collection<V>>.
static class MultimapAdapter implements JsonDeserializer<Multimap<String, ?>>, JsonSerializer<Multimap<String, ?>> {
#Override public Multimap<String, ?> deserialize(JsonElement json, Type type,
JsonDeserializationContext context) throws JsonParseException {
final HashMultimap<String, Object> result = HashMultimap.create();
final Map<String, Collection<?>> map = context.deserialize(json, multimapTypeToMapType(type));
for (final Map.Entry<String, ?> e : map.entrySet()) {
final Collection<?> value = (Collection<?>) e.getValue();
result.putAll(e.getKey(), value);
}
return result;
}
#Override public JsonElement serialize(Multimap<String, ?> src, Type type, JsonSerializationContext context) {
final Map<?, ?> map = src.asMap();
return context.serialize(map);
}
private <V> Type multimapTypeToMapType(Type type) {
final Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
assert typeArguments.length == 2;
#SuppressWarnings("unchecked")
final TypeToken<Map<String, Collection<V>>> mapTypeToken = new TypeToken<Map<String, Collection<V>>>() {}
.where(new TypeParameter<V>() {}, (TypeToken<V>) TypeToken.of(typeArguments[1]));
return mapTypeToken.getType();
}
}
The full code including a test can be found here.
I need to generate the following json files using Javascript serializer,
1. {"components":[{"name":"AA"}]}
2. {"customfield_10222":[{"name":"xxx"},{"name":"yyyy"}]} // this custom field represents the additional notification persons.
I have to achieve this scenario using the below coding,
public List<AdditionalUsers> AdditionalNotification = new List<AdditionalUsers>();
public List<ComponentsDetails> Component = new List<ComponentsDetails>();
class AdditionalUsers
{
public string name;
}
class ComponentsDetails
{
public string name;
}
string[] a=new string[2]{"XXX","YYY"};
foreach (string additionalUser in a)
{
AdditionalNotification.Add(new AdditionalUsers() { name =additionalUser });
}
Component.Add(new ComponentsDetails() { name = "AA" });
var subFields = new Dictionary<string, object>();
subFields.Add("components", Component); // represents 1 json file
subFields.Add("customfield_10222", AdditionalNotification); // represents 2 json file
JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = serializer.Serialize((Object)subFields);
Console.WriteLine(json);
The result like this
{
"components":[{"name": "AA"}],
"customfield_10222":[{"name":"XXX"},{"name":"YYY"}]
}