Sorting in Jackson Library W/O POJO Specified - java

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.

Related

Replace or update an object in a list knowing only its UUID

I know similar questions have been asked already, but every time the answers revolve around "use a Map instead".
In my case, I HAVE to use a List. More precisely, I can use other data structures for treatment, but the information will be stored ultimately in the form of a List.
Here is the situation : I have an object, which I will call Sequence, containing a List of objects I will call Phase.
Among other properties, the Phase object is given a UUID through ObjectId
During a given treatment, I have to replace an existing Phase inside the List<Phase> contained in Sequence by another Phase. The input for this are the replacement Phase object and a String value of the ObjectId of the Phase to replace
I was hoping to be able to do something like this using Java8 :
public void replacePhase(Sequence sequence, Phase replacementPhase, String idPhaseToBeReplaced) {
List<Phase> phaseList = sequence.getPhaseslist();
Phase phaseToBeReplaced = phaseList.stream().filter(p -> p.getId().toString().equalsIgnoreCase(idPhaseToBeReplaced)).findFirst().orElse(null);
if (phaseToBeReplaced != null) {
phaseToBeReplaced = replacementPhase;
}
And voilĂ , the List<Phase> would be updated.
I know something like this will work :
public void replacePhase(Sequence sequence, Phase replacementPhase, String idPhaseToBeReplaced) {
List<Phase> phaseList = sequence.getPhaseslist();
Phase phaseToBeReplaced = phaseList.stream().filter(p -> p.getId().toString().equalsIgnoreCase(idPhaseToBeReplaced)).findFirst().orElse(null);
if (phaseToBeReplaced != null) {
int i = phaseList.indexOf(phaseToBeReplaced );
phaseList.set(i, replacementPhase);
phaseToBeReplaced = replacementPhase;
}
But it doesn't seem more efficient that using a for loop on phaseList with a break when finding a Phase with the desired UUID.
So my question is : is there a way, using List data structure, to find an object based on a (in this case, unique) property and then replace said object inside the List by another (of the same type), preserving order? Preferably without iterating over the whole List and using Java8 functionnalities?
In order to make your replace functionality work in short-circuit fashion, use ListIterator:
ListIterator<Phase> iterator = phaseList.listIterator();
while(iterator.hasNext()){
Phase phase = iterator.next();
if(phase.getId().toString().equalsIgnoreCase(idPhaseToBeReplaced)){
iterator.set(replacementPhase);
break;
}
}
In case the id is not unique, just remove the break. Or use List::replaceAll.
You seem to be looking for List#replaceAll such as :
sequence.getPhasesList()
.replaceAll(phase -> phase.getId().toString()
.equalsIgnoreCase(idPhaseToBeReplaced) ? replacementPhase : phase);
If you keep the list sorted you can find the item using binary search, that would be faster than iterating the list.
Collections.binarySearch
If you need to keep it sorted by insertion order, use a LinkedHashMap

Understanding multidimensional, associative array's in Groovy

First time posting and I am having some difficulty understanding groovy script arrays? (not sure if they are list, arrays, or maps). I have typically coded in PHP and am used to associating PHP multidimensional arrays as a (key => value) association. I am not sure if I am overlooking that flexibility in Groovy. It seems like you either have to pick either a map/array combo or a list.
What I am trying to accomplish is I have another associative array that is static I would like to have associated with a key -> value. (e.g. 1 - Tim, 2 - Greg, 3 - Bob, etc...)
I have another associative array that is total dynamic. This needs to be nested within the associative array that I stated above because in this list it will contain task information that the current user has worked on. (e.g. under Tim there he might have worked on 3 unrelated task at a different time and the statuses of those task might vary. So this should correlate to something like this [Task 1, 3/6/19, Completed Task], [Task 2, 3/5/19, Completed Task], [Task 3, 2/5/19, In Progress Task]. Someone named Greg might have instead 4 task.
So my question is what is the best data structure to use for this? How do I add data to this data structure effectively?
I'm sorry if these seem like bare-bones basic questions. Again, I'm new to Groovy.
Map model=[:]
List names=['Tim','Greg','Bob']
names?.each { name->
//dynamically call something that returns a list
// model."${name}"= getSomeList(name)
//get a list assign it the above list maybe something like this
// List someTasks = ['task1','task2']
// model."${name}"= someTasks
//or shorter
// model."${name}"= ['task1','task2']
// 1 element multi element list
if (name=='Bob') {
model."${name}"= ['task1']
} else {
model."${name}"= ['task1','task2']
}
}
//This iterates through map and its value being another iteration
model?.each{ key,value ->
println "working on $key"
value?.each { v-
println "$key has task ${v}"
}
}
Try some of above may help you understand it better and yes you can use <<
Map model=[:]
model << ['bob':['task1']]
model << ['Greg':['task1','task2']]
You could either map like latter or above through an iteration further lists/maps within that list so for example:
model << ['Greg':[
'task1' : ['do thing1','do thing2'],
'task2': [ 'do xyz', 'do abc']
]
]
//This iterates through map and its value being another map with an iteration
model?.each{ key,value ->
println "working on $key"
value?.each {k, v->
println "$key has task ${k}"
v?.each { vv ->
println "$key has task ${k} which needs to do ${vv}"
}
}
}
Using collect you could really simply all the each iterations which is a lot more verbose, using collection you could make it into one line:
names?.collect{[it:getSomeList(it)]}
//sometimes you need to flatten in this case I dont think you would
names?.collect{[it:seriesHotelList(it)]}?.flatten()
List getSomeList(String name) {
return ['task1','task2']
}
The basic data structures that are key/value lookups are just Java Maps (usually the LinkedHashMap implementation in Groovy). Your first-level association seems to be something like a Map<Integer, Employee>. The nested one that you are calling "total dynamic" seems instead to really be a structured class, and you definitely should learn how Java/Groovy classes work. This seems to be something like what you're looking for:
class Employee {
int employeeId
String name
List<Task> tasks
}
enum TaskStatus {
PENDING,
IN_PROGRESS,
COMPLETED
}
class Task {
int taskNumber
LocalDate date // java.time.LocalDate
TaskStatus status
}
By the way, Groovy is a great language and my preferred JVM language, but it's better to make sure you understand the basics first. I recommend using #CompileStatic on all of your classes whenever possible and making sure you understand any cases where you can't use it. This will help to prevent errors and missteps as you learn.

Why doesn't the Java library provide `HashSet.get(Object o)` and `HashMap.getKey(Object o)`

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.

Keeping track of pairs of Strings

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

Is there any java library which can apply a visitor function to multiple elements of a pre-generics collection?

I deal a lot with the pre-generics like Maps with Strings as the keys. They are mapping the keys to one of the following types of values:
Another Map
A List
Primitives wrappers
You can access the collection content using either XPath or queries like that:
myMap/FIRST_LIST[2]/SECOND_LIST[1]/MY_MAP/MY_PRIMITIVE
What I am looking for is a library that would allow me to apply a visitor function to the multiple elements of a collection. The basic functionality could look like that
MyMapBrowser browser = new MyMapBrowser(myMap);
browser.applyVisitor("FIRST_LIST[*]/SECOND_LIST[*]/MY_MAP/MY_PRIMITIVE",
new AbstractVisitor<String>() {
visit(String s) {
// do something with the strings
}
});
It would be also wonderful to have a possibility to first register multiple visitors for various levels of collection and then start the visiting iteration. It could look like this:
browser.registerVisitor(SECOND_LIST, new AbstractVisitor<MyList> { ... )
browser.doVisiting("FIRST_LIST[*]/SECOND_LIST[*]/MY_MAP/MY_PRIMITIVE");
In fact I've already started implementing a browser like that but I can't get rid of an impression that I'm reinventing the wheel.
Have you looked into JXPath? It lets you use XPath expressions to query and manipulate Java object graphs. The JXPathContext class lets you iterate over the values of selected nodes if you just want to extract the string values, or you can use the selectNodes method to get JDOM wrappers.
For instance, I think your example query would look something like:
// untested
JXPathContext context = JXPathContext.newContext(myMap);
Iterator iter = context.iterate("FIRST_LIST/SECOND_LIST/MY_MAP/MY_PRIMITIVE");
while (iter.hasNext()) {
String str = (String) iter.next();
// do something with strings
}
Unfortunately I haven't actually worked with JXPath (though I've also tried implementing an XPath-like traverser before too), but apparently you can also configure it to automatically create objects for a particular path. I didn't see any visitor functionality, but the iterate, getValue, and setValue should be able to accomplish the same thing. You could also rig up a simple wrapper class to run the query, iterate through the nodes, and pass the values to your own visitor interface. Something like:
public class JXPathVisitBrowser {
private JXPathContext context;
public JXPathVisitBrowser(Object object) {
context = JXPathContext.newContext(object);
}
public <T> void applyVisitor(String query, AbstractVisitor<T> visitor) {
Iterator iter = context.iterate(query);
while (iter.hasNext())
visitor.visit((T) iter.next());
}
}
There's a pretty detailed JXPath user guide too.
Take a look on LambdaJ. I think this is what you are looking for.

Categories

Resources