Mapping String to String value - java

Here is my problem:
I have list of possible Product categories(for example: Shoes,Mode,Women), and I need to convert this to my specific names.
example: I get the category Women and I need to convert this to Lady's.
I have about 40 category names that i need to convert.
My question is :What is the best way to do this in JAVA.
I thought about switch case, but i dont know is this a good solution.
switch (oldCategoryName) {
case "Women":
return "Ladys";
default:
return "Default";
}

You can use static map for that.
Make a Static Map as below
public class PropertiesUtil {
private static final Map<String, String> myMap;
static {
Map<String, String> aMap = new HashMap<String, String>();
aMap.put("Women", "Ladys");
aMap.put("another", "anotherprop");
myMap = Collections.unmodifiableMap(aMap);
}
}
then get the replacing string..
String womenReplace = PropertiesUtil.myMap.get("Women");

You can also consider using enums:
public enum ProductsCategory {
Mode("MyMode"),
Shoes("MyShoes");
private String name;
private ProductsCategory(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Then the retrieval:
String myModeStr = ProductsCategory.Mode.getName();

Note that the java switch does not work on String objects for java versions below 7.
You can store values in a map :
// storing
Map<String, String> map = new HashMap<String, String>();
map.put("Women", "Ladys");
// add other values
// retrieving
String ladys = map.get("Women");
Or you can also use a .properties file to store all those associations, and retrieve a property object.
InputStream in = new FileInputStream(new File("mapping.properties"));
Properties props = new Properties();
props.load(in);
in.close();
String ladys = props.getProperty("Women");

Related

groupping list of objects based on properties in java

I have POJO List<TravelRequestDTO> and I want to group and create filtered List<TravelRequestDTO> if leavingFrom,goingTo,onwarDate,returnDate are same add passenger to same object
Example :
Passanger, onWard, return, leavingFrom, goingTo
A, 1-2-20, 3-2-20, BLR, PUNE
B, 1-2-20 , 3-2-20, BLR, PUNE
final List<TravelRequestDTO> should contain :
Passanger, onWard, return, leavingFrom, goingTo
A,B 1-2-20 3-2-20 BLR PUNE
public class TravelRequestDTO {
private List<Pax> passangers;
private String leavingFrom;
private String goingTo;
private String onwarDate;
private String onwardTime;
private String returnDate;
private String returnTime;
private SegmentTypeEnum segmentType;
private TravelModeEnum travelMode;
private String purposeOfVisit;
}
public class Pax{
private String name;
private String age;
private String mobile;
}
If you need older java version, than you can do like this:
Map<Object, List<TravelRequestDTO>> hashMap = new HashMap<Object, List<TravelRequestDTO>>();
for (TravelRequestDTO value: initList) {
List<Object> key = Arrays.asList(value.getOnWard(),value.getReturn(),value.getLeavingFrom(),value.getGoingTo());
if (!hashMap.containsKey(key)) {
List<TravelRequestDTO> list = new ArrayList<TravelRequestDTO>();
list.add(value);
hashMap.put(key, list);
} else {
hashMap.get(key).add(value);
}
}
Check this question for other solution.
It is only half way to what you want. After that you have to extract final result from this map. Or you can do it in one step:
Map<Object, TravelRequestDTO> hashMap = new HashMap<Object, TravelRequestDTO>();
for (TravelRequestDTO value: initList) {
List<Object> key = Arrays.asList(value.getOnWard(),value.getReturn(),value.getLeavingFrom(),value.getGoingTo());
if (!hashMap.containsKey(key)) {
TravelRequestDTO item = value; // pass first value or copy it to new
hashMap.put(key, item);
} else {
hashMap.get(key).getPassangers().addAll(value.getPassangers());
}
}
List<TravelRequestDTO> result = new ArrayList<>(hashMap.values());
you can use the below code to get a List of TravelRequestDTO objects based on properties.
Function<TravelRequestDTO, List<Object>> compositeKey = travelRecord ->
Arrays.<Object>asList(travelRecord.getOnWard(),travelRecord.getReturn(),travelRecord.getLeavingFrom(),travelRecord.getGoingTo());
Map<Object, List<TravelRequestDTO>> map =
people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));

Declare Map fields with type system

In Java say I have a class that represents http headers:
public class Headers {
String 'x-requested-by' = "foo";
String 'content-type' = "application/json"
}
because of the field names with non-standard variable names (hyphens), typically a more dynamic map is used like so:
Map<String, String> map = new HashMap<String, String>();
but my quesetion is - is there a way to declare which fields will exist in there statically, instead of only at runtime?
You can use an enum map, which will only accept keys of a specified enum type, while the enum itself will statically limit options.
enum Headers {
X_REQUESTED_BY("x-requested-by"), CONTENT_TYPE("content-type");
private String headerName;
private Headers(String n) {
this.headerName = n;
}
public String getHeaderName() {
return headerName;
}
}
And use the enum map to store values:
Map<Headers, String> headerValues = new EnumMap<>(Headers.class);
Your API can then be extended with such methods as addHeader(Headers h), which makes it possible to statically limit options while keeping it type-safe.
No. Only one thing you can do is init a Map with default values after initialization.
public class Header {
public static final String X_REQUESTED_BY = "x-requested-by";
public static final String CONTENT_TYPE = "content-type";
private final Map<String, String> map = new HashMap<String, String>();
{
map.put(X_REQUESTED_BY, "foo");
map.put(CONTENT_TYPE, "application/json");
}
}

Java streams: Add to map but avoid mutation

I often find myself in a situation where I need to create a Map of objects from a Set or List.
The key is usually some String or Enum or the like, and the value is some new object with data lumped together.
The usual way of doing this, for my part, is by first creating the Map<String, SomeKeyValueObject> and then iterating over the Set or List I get in and mutate my newly created map.
Like the following example:
class Example {
Map<String, GroupedDataObject> groupData(final List<SomeData> list){
final Map<String, GroupedDataObject> map = new HashMap<>();
for(final SomeData data : list){
final String key = data.valueToGroupBy();
map.put(key, GroupedDataObject.of(map.get(key), data.displayName(), data.data()));
}
return map;
}
}
class SomeData {
private final String valueToGroupBy;
private final Object data;
private final String displayName;
public SomeData(final String valueToGroupBy, final String displayName, final Object data) {
this.valueToGroupBy = valueToGroupBy;
this.data = data;
this.displayName = displayName;
}
public String valueToGroupBy() {
return valueToGroupBy;
}
public Object data() {
return data;
}
public String displayName() {
return displayName;
}
}
class GroupedDataObject{
private final String key;
private final List<Object> datas;
private GroupedDataObject(final String key, final List<Object> list) {
this.key = key;
this.datas = list;
}
public static GroupedDataObject of(final GroupedDataObject groupedDataObject, final String key, final Object data) {
final List<Object> list = new ArrayList<>();
if(groupedDataObject != null){
list.addAll(groupedDataObject.datas());
}
list.add(data);
return new GroupedDataObject(key, list);
}
public String key() {
return key;
}
public List<Object> datas() {
return datas;
}
}
This feels very unclean. We create a map, and then mutate it over and over.
I've taken a liking to java 8s use of Streams and creating non-mutating data structures (or rather, you don't see the mutation). So is there a way to turn this grouping of data into something that uses a declarative approach rather than the imperative way?
I tried to implement the suggestion in https://stackoverflow.com/a/34453814/3478016 but I seem to be stumbling. Using the approach in the answer (the suggestion of using Collectors.groupingBy and Collectors.mapping) I'm able to get the data sorted into a map. But I can't group the "datas" into one and the same object.
Is there some way to do it in a declarative way, or am I stuck with the imperative?
You can use Collectors.toMap with a merge function instead of Collectors.groupingBy.
Map<String, GroupedDataObject> map =
list.stream()
.collect(Collectors.toMap(SomeData::valueToGroupBy,
d -> {
List<Object> l = new ArrayList<>();
l.add(d.data());
return new GroupedDataObject(d.valueToGroupBy(), l);
},
(g1,g2) -> {
g1.datas().addAll(g2.datas());
return g1;
}));
The GroupedDataObject constructor must be made accessible in order for this to work.
If you avoid the GroupedDataObject and simply want a map with a key and a list you can use Collectors.groupingBy that you have been looking into.
Collectors.groupingBy will allow you to do this:
List<SomeObject> list = getSomeList();
Map<SomeKey, List<SomeObject>> = list.stream().collect(Collectors.groupingBy(SomeObject::getKeyMethod));
This will require SomeKey to have proper implementations of equals and hashValue
Sometimes streams are not the way to go. I believe this is one of those times.
A little refactoring using merge() gives you:
Map<String, MyTuple> groupData(final List<SomeData> list) {
Map<String, MyTuple> map = new HashMap<>();
list.forEach(d -> map.merge(d.valueToGroupBy(), new MyTuple(data.displayName(), data.data()),
(a, b) -> {a.addAll(b.getDatas()); return a;});
Assuming a reasonable class to hold your stuff:
class MyTuple {
String displayName;
List<Object> datas = new ArrayList<>();
// getters plus constructor that takes 1 data and adds it to list
}

Accessing Nested Java HashMap Key Value pairs

Okay, I'm SURE there is a better way to do this. What I have is a nested HashMap which contains any number of K,V pairs as imported from an XML file. However for each Key in the parent HashMap, there is only 1 child K,V pair.
I'm wondering if there is a "better" way to code this than what I have.
HashMap<String, HashMap<String,String>> mQueues = Global.mQueues;
for (Map.Entry<String, HashMap<String, String>> eQueues: mQueues.entrySet()) {
// There is only 1 K,V for each key iterated above
// This is where I am wondering if there is a better way to do this. e.g. directly access the Key and Value of the subordinate HashMap
for (Map.Entry<String, String> sQueue : eQueues.getValue().entrySet()) {
strGroup = sQueue.getKey();
strPattern = sQueue.getValue();
}
if (eQueues.getKey() == "Default") {
strDefGroup = strGroup;
} else {
if (strParts[0] == strPattern) {
msg_grp = strGroup;
boolPatternMatch = true;
}
}
Well, you could do this:
Map<String, String> m = eQueues.getValue();
if (!m.isEmpty()) {
Map.Entry<String, String> e = m.entrySet().iterator().next();
}
That's not really any better than what you're doing, though. It seems like instead of a Map<String, Map<String, String>> you should have a Map<String, Map.Entry<String, String>>, or even just create a small object to describe whatever it is that's in your single entry:
public class GroupPattern {
private String group;
private String pattern;
public GroupPattern(String group, String pattern) {
this.group = group;
this.pattern = pattern;
}
public String getGroup() {
return group;
}
public String getPattern() {
return pattern;
}
// Optionally setters, if it makes sense.
public void setGroup(String group) {
this.group = group;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
}
Then you have a Map<String, GroupPattern>.
Also, what Elliott is saying in the comments is right. See e.g. How do I compare strings in Java?

how to ignore null when deserializing from json string to object?

I have a class defined as below:
// Ignore all the unknown properties in input JSON
#JsonIgnoreProperties(ignoreUnknown = true)
// Only include non null values in deserialized Java object.
#JsonInclude(value = Include.NON_NULL)
public class Person {
#JsonProperty("person_id")
private String personId;
#JsonProperty("school")
private String school;
#JsonProperty("hobbies")
private Map<String, List<AttributeBag>> hobbies = new HashMap<String, List<AttributeBag>>();
#JsonProperty("tasks")
private Map<String, Map<String, AttributeBag>> tasks = new HashMap<String, Map<String, AttributeBag>>();
public Map<String, List<AttributeBag>> getHobbies() {
return hobbies;
}
public Person(String person_id, String school) {
super();
this.person_id = person_id;
this.school = school;
}
When I use a JSON string below to deserialize from string to object,
{
"person_id":"123",
"school":"stanford University"
}
From the object I got deserialized, the hobbies is create but empty, and the tasks is not created even. I am expecting the way like "tasks", if there is no corresponding field in JSON, it SHOULD NOT get deserialized in the object.
But the weird thing is : when I check object.getHobbies()!=null but the tasks part is null. I want both are null in the object if they were not present in JSON.
I have a constructor for the Person class but I did not initialize both hobbies and tasks part.
Thanks a lot
#JsonProperty("hobbies")
private Map<String, List<AttributeBag>> hobbies = new HashMap<String, List<AttributeBag>>();
#JsonProperty("tasks")
private Map<String, Map<String, AttributeBag>> tasks = new HashMap<String, Map<String, AttributeBag>>();
from above code its clear that you are creating new objects for hobbies and tasks no matter what, I am not able to understand why your tasks are not created(it should get created as a empty map)
and to answer your question #JsonInclude(value = Include.NON_NULL) should do the trick!
The JSON deserialiser will not attempt to set the fields that don't appear in the JSON structure, but these lines:
#JsonProperty("hobbies")
private Map<String, List<AttributeBag>> hobbies = new HashMap<String, List<AttributeBag>>();
#JsonProperty("tasks")
private Map<String, Map<String, AttributeBag>> tasks = new HashMap<String, Map<String, AttributeBag>>();
are creating the values on object construction.
If you want them to be null then don't allocate them in the object, just leave the declaration:
#JsonProperty("hobbies")
private Map<String, List<AttributeBag>> hobbies;
#JsonProperty("tasks")
private Map<String, Map<String, AttributeBag>> tasks;

Categories

Resources