My current project requires me to utilize pairs of Strings for various use cases. I am currently using the Apache Lang3 Pair tuple to handle this case. The current implementation looks like the following
private List<Pair<String, String>> configParameters;
private List<Pair<String, String>> sensorReadingMeasures;
After discussion with the rest of the team it was decided that because we would need to expose these pairs of strings it would be best to find native Java solution.
I have attempted to find a solution using the AbstractMap in the java util library but I haven't had much luck being able to instantiate it, and a google search hasn't provided much information on helping me along.
I have attempted to recreate the above by doing,
AbstractMap<String, String> pair = new AbstractMap<String, String>();
I would be able to pull the required information using the keyset() function and pulling the needed information out by the get() function for each key value.
Beyond my instantiation problem this seems like a terribly inefficient way to get the same functionality, and I am curious if there is a better option. If there isn't can someone please provide an example on how to instantiate an AbstractMap appropriately.
If one of the two strings in each pair is unique, as your suggestion to use an AbstractMap seems to suggest, you may want to expose an API that returns Map<String,String>, and use an implementation of your choice for that interface (say, LinkedHashMap<String,String>).
The users of your class would be able to pull the pairs of Strings from the Map by using Map.Entry<String,String>, rather than calling a get for each key:
Map<String,String> getAllPairs() {
...
}
...
for (Map.Entry<String,String> pair : myClass.getAllPairs()) {
// You can use pair.getKey() and pair.getValue() here
}
Can you not just use a POJO:
public class Tuple {
public String oneString;
public String otherString;
}
You can have lists of them:
public List<Tuple> tuples = new ArrayList<Tuple>();
Or you can have Collections of them that can be searched if you:
#Override
public boolean equals(Object obj) {
// Code to handle non-Tuples and null goes here
// Code to handle null oneString values goes here (if you allow that)
return ((Tuple)that).oneString.equals(oneString);
}
#Override
public int hashCode() {
// handle null oneString values here
return oneString.hashCode();
}
Related
I would like to know how sorting in the jackson library works.
What I have is a json like the below(no POJO equivalent of this json exists), and I would like to sort the array 'ItemProps', even though sometimes it might contain the properties in different order.
{
"ItemId":"<item_id>",
"ItemProps":[
{
"key":"property_key",
"value":"property_value"
},
{
"key":"property_key",
"value":"property_value"
}
]
After quite a bit of reading, I found that this can be achieved by creating a deterministic mapper object by setting the properties to true
ORDER_MAP_ENTRIES_BY_KEYS
SORT_PROPERTIES_ALPHABETICALLY
I've wrote few unit tests and found it to be working as expected.
But I am wondering how the sorting of the ItemProps works internally?
Is it by
hashcode of the individual json objects
takes one or more fields as references and does comparison?
I searched about it and couldn't find anything on it.
Any pointers to any articles or answers will be helpful.
Thanks.
But I am still curios as to how this sorting works.
You can check the source code from the jar file. I was curious & just took a look at jackson-databind-2.6.6.jar.
If you are not deserializing map to an instance of SortedMap, ORDER_MAP_ENTRIES_BY_KEYS will use a TreeMap to sort it out & return the sorted result.
protected Map<?,?> _orderEntries(Map<?,?> input)
{
// minor optimization: may already be sorted?
if (input instanceof SortedMap<?,?>) {
return input;
}
return new TreeMap<Object,Object>(input);
}
SORT_PROPERTIES_ALPHABETICALLY will also sort the results using TreeMap.
int size = props.size();
Map<String, POJOPropertyBuilder> all;
// Need to (re)sort alphabetically?
if (sort) {
all = new TreeMap<String,POJOPropertyBuilder>();
} else {
all = new LinkedHashMap<String,POJOPropertyBuilder>(size+size);
}
Remember, this is internal & in later version implementation can change.
I know this question has already been asked on SO a couple of times, but I still haven't found a satisfying solution, and I'm unsure which way to go. The question is:
Why doesn't the Java library provide HashSet.get(Object o) and HashMap.getKey(Object o) methods that return the actual instance in the map providing an equal instance? Example:
// Retrieve a house with ID=10 that contains additional information like size,
// location and price.
houses.get(new House(10));
I think the best answer can be found here. So here's a mixture of answers that I'm aware of:
Why would you need the instance when you already have it? It doesn't make sense to try to get the same object you already have. The object has an identifier (which controls it's equality to other Foo types) plus any number of other fields that do not contribute to it's identity. I want to be able to get the object from the Set (which includes the extra fields) by constructing an 'equal' Foo object (text is taken from one of the comments). -> no answer
Iterate the Collection and search for the instance using equals(). This uses linear search and is extremely slow in big collections. -> bad answer
Use a HashMap instead of a HashSet I don't need a map and I think it's not adequate to return a map in a method like getHouses(). The getter should return a Set and not a Map.
Use TreeSet.ceiling - don't know
This hacky code below (Java 8 HashSet only) uses reflection and provides the missing functionality. I did not find something like this in other answers (no surprise). This could have been an acceptable solution if the target Java version is defined and future Java versions would finally provide such a method, now that we have default methods for interfaces. One could think of default E get(E o){stream().filter(e->e.equals(o)).findAny().orElse(null);}
// Alternative: Subclass HashSet/HashMap and provide a get()/getKey() methods
public static <T> T getFromSet(HashSet<T> set, T key) throws Exception {
Field mapField = set.getClass().getDeclaredField("map");
mapField.setAccessible(true);
HashMap<T, Object> map = (HashMap) mapField.get(set);
Method getNodeMethod = map.getClass().getDeclaredMethod("getNode",
int.class, Object.class);
getNodeMethod.setAccessible(true);
return (T) ((Map.Entry) getNodeMethod.invoke(map, key.hashCode(),
key)).getKey();
}
Here are the questions:
Is the best solution the use of HashMap<House, House> instead of HashSet<House>?
Is there another library out there that provides this functionality and supports concurrent access?
Do you know of a bug addressing this feature?
Similar questions on SO:
Why doesn't java.util.HashSet have a get(Object o) method?
Java: Retrieving an element from a HashSet
Why does the java.util.Set interface not provide a get(Object o) method?
The reason this behaviour hasn't been catered for is that creating a House instance with invalid data just to obtain one with valid data is really poor design.
Composition is the correct solution here:
/** immutable class containing all the fields defining identity */
public final class HouseIdentifier {
private final String id;
}
public class House {
private final HouseIdentifier id;
/** all the mutable, ephemeral properties of the house should go here */
private int size;
private Person owner;
}
If you design your class hierarchy like this, then all you need for your lookups is a simple and straightforward Map<HouseIdentifier, House>.
Map doesn't have a getKey(Object o) because it's not a bidirectional map. It only maps keys to values, not the other way around.
Set doesn't have get(Object o) because that's the job for a Map.
Mapping a House object to another House object is just bad design on your part. You want to get a House by an address or a number or similar, so you have one or more maps that give you those mappings (or more likely, a database). Your question makes sense only to you, because you're thinking "in the wrong way".
Your "wrong way of thinking" is evidenced by your statement
I don't need a map and I think it's not adequate to return a map in a
method like getHouses(). The getter should return a Set and not a Map.
I have never heard that a getter can't return a Map. Although I would probably name it getHouseMap(). You're creating a huge problem out of a trivial little issue. This is the job for a database anyways, so your dataset must be quite small.
Hi I am having 3 attributes (String) that are needed to identify a certain Object.
What is the better solution:
using a key object as those post by Pierre and Joachim Sauer like this:
public class MyKey{
private String one;
private String two;
private String three;
public MyKey(Sting one,String two, String three){
this.one=one;
this.two=two;
this.three=three;
}
//getter only
#Override
public int hashcode(){
// creating Hashcode
}
#Override
public boolean equals(Object o){
// comparing
}
}
=> Map<MyKey, Object>
or using a Map inside a Map inside a Map:
=> Map<String, Map<String, Map<String, Object>>>
I think you should go with the first option. Reason being that it is more clean and flexible. Imagine a few months down the line you need to add an extra element to your key, your structure would now be invalid since it requires one more level of nesting, not to mention making it more complex.
I would go with the key class as you have specified. It's much clearer and has the advantage of being able to name the keys.
You said
I am having 3 attributes (String) that are needed to identify a
certain Object.
That immediately indicates to me that your key consists of three strings, and your first solution is correct and intuitive.
just implement equals
one.equals(o) || two.equals(o) || three.equals(o)
and hashcode
one.hashCode() ^ two.hashCode() ^ three.hashCode()
If you always need the 3 keys you should use a key object (tuple-3) for performance reasons. One object to rule them all...
Also make each key field final if you want better concurrency (you could even pre-compute the hash...)
I have a String array (String[]) containing several String objects representing XPath queries. These queries are predetermined at design time. This array is passed to an object who executes the queries and then returns a Map<String, ArrayList<String>> with the results.
The map is made like this:
{Query that originated the result, Results vector}
Since I have to take these results and then perform some work with them, I need to know the individual queries. e.g.:
ArrayList<String> firstQueryResults = xpathResults.getObject(modelQueries[0]);
... logic pertaining only to the first query results ...
Retrieving the results by an integer (in the case of the first query, "0") doesn't seem nice to me, so I was wondering if there would be the possibility to identify them via enum-like constants, for better clarity:
... = xpathResults.getObject(QueryDictionary.MODEL_PACKAGE);
... = xpathResults.getObject(QueryDictionary.COMPONENT_PACKAGE);
OR
... = xpathResults.getObject(ModelQueries.PACKAGE);
... = xpathResults.getObject(ComponentQueries.PACKAGE);
I thought of using maps (i.e. Map<String, String> as in Map {ID, Query}) but I have still to reference the queries via an hardcoded string (e.g. "Package").
I also thought of using enums but i have several query sets (Model, Component, ...) and I also need to get all the query in a set in a String[] form in order to pass them to the object who performs the queries.
You can use a marker interface:
public interface QueryType {
}
Then your enums can implement this interface:
public enum ModelQueries implements QueryType {
...
}
public enum ComponentQueries implements QueryType {
...
}
and so on.
Then your getObject method can accept a parameter of type QueryType. Were you looking for something like this? Let me know if I haven't understood your question properly.
Is there a library that can do the following?:
Given an Object and a HashMap, it enumerates the keys of the Hashmap and looks up the setters for these keys in the Object and sets the associated values. Something looking like that:
public Object setData(Object object, HashMap<String, Object> fields) {
for (Entry<String, Object> entry : fields.entrySet()) {
Method m = object.getClass().getMethod("set" + entry.getKey(), entry.getValue().getClass());
if (m != null) {
m.invoke(object, entry.getValue());
}
}
return object;
}
The task looks simple at the first look but there are some nuances that I hope someone has already taken care of. As you know, reinventing the wheel (the good wheel) is a bad approach.
Look at Apache Commons BeanUtils
org.apache.commons.beanutils.BeanUtils.populate(Object bean, Map properties)
Javadoc:
Populate the JavaBeans properties of the specified bean, based on the specified name/value pairs. This method uses Java reflection APIs to identify corresponding "property setter" method names, and deals with setter arguments of type String, boolean, int, long, float, and double.
Better use BeanUtils class:
public Object setData(Object object, HashMap<String, Object> fields) {
for(Entry<String, Object> entry : fields.entrySet()) {
BeanUtils.setProperty(object, entry.getKey(), entry.getValue());
}
return object;
}
I have a BeanAsMap class that I wrote a long time ago. The method asMap returns a Map that is a view on a Java bean (POJO). You can call putAll on that Map, passing it the Map that you want to copy data from.
Feel free to use my code mentioned above.
Example:
MyClass bean = ...;
Map<String, Object> inputData = ...;
Map<String, Object> view = BeanAsMap.asMap(bean);
view.putAll(inputData);
BeanUtils is fine.
But, as good practice, i would not write code that use reflection. Or as the last solution i have, if none other has been found.
This code cannot be tracked in IDE like Eclipse (no call hierarchy), making the developer think that the setters are never called. He can break your code and that will still compile.
Too high level of abstraction like this makes the code difficult to understand.
Code that is being obfuscated will be broken by the obfuscator itself when writting such things.
Best solution would be to rethink the use of reflection to set the object fields.
Check out http://commons.apache.org/beanutils/, in particular BeanUtils.populate():
http://commons.apache.org/beanutils/v1.8.3/apidocs/index.html