Sharing a hashmaps and some other data structures among different classes - java

In a web application I want to execute some methods, that belong to different classes. Method calls will be made in a chain (1st method calls 2nd, 2nd calls 3rd... and so on). Each method is going to make some entries or updates in some hashmaps or other data structures. After all the methods are executed, I have to make some updates in my database. Based on values stored in hashmaps.
As per my understanding, I have below options to achieve this:
Keep passing the hashmaps, from one method to other.
I think it's a bad approach.
Keep those hashmaps in separate class. Create an object of that class and keep that object passing from one method to other and so on.
This approach looks better than 1st to me but it still involves passing an object from one object to other leading to a tightly coupled design.
Using static hashmaps
(or hashtables) or static object of the seperate class made as in option 2.
(This I think is worse approach because static variables will be shared aming different users).
Please help me in understanding the best approach.

You can apply builder pattern to avoid passing parameters between methods. It gives the opportunity of building all your necessary operations in one class and calling them in chain.
Assuming you have 3 operations on the map, I have demonstrated the use of builder design pattern in this scenario
public class MyMap {
Map<String, String> map;
public MyMap(MyMapBuilder builder) {
this.map = builder.map;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public static class MyMapBuilder {
Map<String, String> map;
public MyMapBuilder() {
this.map = new HashMap<String,String>();
}
public MyMapBuilder doOperationOne() {
new OperationOne().run(map);
return this;
}
public MyMapBuilder doOperationTwo() {
new OperationTwo().run(map);
return this;
}
public MyMapBuilder doOperationThree() {
new OperationThree().run(map);
return this;
}
public MyMap build() {
return new MyMap(this);
}
}
}
Here is your operation classes (dummy operations as example)
public class OperationOne {
public void run(Map<String, String> map) {
map.put("OpOne", "1");
}
}
public class OperationThree {
public void run(Map<String, String> map) {
map.put("OpThree", "3");
}
}
public class OperationTwo {
public void run(Map<String, String> map) {
map.put("OpTwo", "2");
}
}
And here is how it is called at final
MyMap resultMap = new MyMap.MyMapBuilder().doOperationOne().doOperationTwo().doOperationThree().build();
The resultMap object keeps the result Map.

If you want to go the OO route, you shouldn't think about the problem as "data" going through transformations.
Think about what all of that means. Make it a collaboration between objects that mean something in your domain. What is the thing that you want in the end? A Report? A Chart? A Price? Call it by name and create it.
Similarly, do not have transformations. You can name (and create) intermediary results, if that makes sense from the domain's point of view. For example to create a Report, you might need a Template first, or whatever.
In short, neither of those solutions look particularly object-oriented to me. But, you can call it functional (if the methods are pure functions), in which case solution #1 or #2 both could work.

Changing multiple internal data structures (belonging to different classes) makes the processing of the incoming web request as fully stateful. It might lead into concurrency issues OR slowness (if you take care of all locks). If the final goal is to make some updates to a database, then either you make them synchronously within the flow OR 'queue' up those events (internally/externally) and process them asynchronously. Each queue record, can hold the info about the DB update. To me, your use case is very similar to 'logging'. A logging framework also needs to make updates to a log file from multiple methods (while processing a single request).

Related

How to detect if a list is changed?

I have a List field in a class managed by a little-known proprietary framework.
The annotation #BindMagic is managed by the framework, so the underlying list mutates sometimes: it could be recreated or its elements could change.
class SharedEntity{
#BindMagic // this annotation does a magic that we cannot control
private List<Map<String,Object>> values;
public boolean isChangedSincePreviousCall(){
// check if "values" have changed since the previous call of this method
}
}
I'm agree that it is a poor design, but let's suppose there's no possibility to affect it.
Time to time (not on every mutation) it's needed to check if the list is changed. For instance, I want do it with the method isChangedSincePreviousCall.
Probably, something like a hash sum would be good. But I'm curious are there better ways.
What is the best practice to detect if the list is changed?
Using a hash is not definitive, because the same hash can be produced from different inputs, albeit with a very small chance.
"Being changed" and "being different" mean different things. Consider an entry in one of the maps that is changed from "A" -> 1 to "A" -> 2 then back to "A" -> 1 again between calls to your method - it was changed but isn't different. I'll assume you mean "different".
Make a copy when checking and compare that with the current state. Assuming that the map values are immutable:
class SharedEntity {
#BindMagic
private List<Map<String, Object>> values;
private List<Map<String, Object>> valuesCopy;
public boolean isChangedSincePreviousCall() {
newCopy = new ArrayList<>(values);
boolean result = !Objects.equals(valuesCopy, newCopy);
valuesCopy = newCopy;
return result;
}
}
If the Map values are (or contain) mutable objects, you'll have to make a deep copy of them when creating the copy.
FYI Objects#equals() returns true if both parameters are null.
The problem is probably the Thread accessing the list. It is most likely not supposed to be caught up in some kind of Listener-resolution, which is why there is no proper way of attaching a listener to the list.
However, if you have control over the SharedEntiry class, you could 'hack' into the list's access by using synchronized. However you expressly stated, that the list could be recreated, so I assume the instance stored behind values can actually be replaced.
Basically you have three cases:
1 The values-List is replaced by a new List:
Solve this by making a second reference on List:
private List<Map<String,Object>> valuesPrevious;
Whenever you check for change, check for identity of the lists first. If they are a mismatch, you can be sure the list changed (at least the instance, if not the content).
if (values != valuesPrevious) {
// handle change.
}
Yes, you still need to periodically check, but an identity-comparison is relatively cheap, and therefore an affordable thread to run in the background.
2 The values-List is replaced by a new List (of a type you did not set):
If that occures, move all values from the API's list to an instance of your observable list (described below), set values to that instance and wait for the next change to occure.
3 The values changed, but the instance is the same:
Solve this by using an ObservableList (if you are implementing in Java10+ https://docs.oracle.com/javase/10/docs/api/javafx/collections/ObservableList.html) or by implementing such a List yourself (probably by extending an existing List type).
Then, that listener only sets a 'dirty' flag, and your method knows that a change occured (and resets the flag).
In any way, my suggestion would be to ensure, that the Thread handling the change only triggers another Thread to handle the change, rather than lock the accessing thread, since I suspect, that your #BindMagic-API has some sort of runtime-relevant factor (for example, it is a network or database related shadow of something).
If you simply lock the thread, until you have handled your reaction, you might get weird effects, disconnects or end up accidentally blocking the server you are accessing.
I would try to use PropertyChangeListener objects. Here is an example for SharedEntity class. You can apply the same for the objects stored in list.
class SharedEntity {
private List<Map<String,Object>> values;
private PropertyChangeSupport pcs = new PropertyChangeSupport();
public void setValues(List<Map<String,Object>> values) {
List<Map<String,Object>> oldValues = this.values;
this.values= values;
pcs.firePropertyChange("values",oldValues, values);
}
public void addValue(Map<String, Object> value) {
// store old
// add new element
// fire change
}
public void removeValue(Map<String, Object> value) {
// store old
// remove value
// fire change
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
}
You can use Observer Pattern to detect change in values.
You need to create Observable.
package com.psl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
public class MyList extends Observable{
private List<Map<String,Object>> values;
public List<Map<String, Object>> getValues() {
return values;
}
public void setValues(List<Map<String, Object>> values) {
if(getValues()==null && values!=null){
setChanged();
notifyObservers();
}
else if( !this.values.equals(values)){
setChanged();
notifyObservers();
}
this.values = values;
}
public static void main(String[] args) {
MyList myList = new MyList();
List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
Notify notify = new Notify();
myList.addObserver(notify);
Map<String, Object> map = new HashMap<String, Object>();
map.put("string_value", null);
myList.setValues(values);
}
}
You have to create observer which will observe changes in MyList
package com.psl;
import java.util.Observable;
import java.util.Observer;
public class Notify implements Observer{
#Override
public void update(Observable o, Object arg) {
System.out.println("List has been changed");
}
}
For more information about Observable Pattern https://springframework.guru/gang-of-four-design-patterns/observer-pattern/

Interface to enforce generic static method in Java

I have a Java class Model which models some data from my remote database. I want all data models in my project to be able to supply a builder from a Map<String, Object> instance (in practice, I'm working with SnapshotParser<Model> parsers with Firestore, but I'll just call getData() in every model). This should look something like:
public class Model {
private String name;
public Model(String name) { this.name = name; }
public static SnapshotParser<Model> getDocParser() {
return docSnapshot -> {
Map<String, Object> data = docSnapshot.getData();
return new Model(data.getOrDefault("name", "John Doe"));
};
}
}
Note that I'll have several models (Model2, Model3...) which will also be required to provide such an interface. To enforce this behavior, I created a DocParserSupplier generic class for my model classes to implement:
public interface DocParserSupplier<T> {
static SnapshotParser<T> getDocParser();
}
This doesn't work for two reasons (as Android Studio informs me):
static methods of interfaces must have a default implementation. I can't do that without knowing T.
I get the "T cannot be referenced in static context" error.
If remove the static keyword from the above interface, I can do what I want but it would require I create an actual instance of the Model to get the parser. It would work but it makes more sense if the method is static.
Is there a Java way to do what I want?
EDIT: My specific use case is in matching RecyclerViews to documents in my database. Constructing the FirestoreRecyclerOptions object requires a parser to convert key-value data to a Model:
FirestoreRecyclerOptions<Model1> fro1 = new FirestoreRecyclerOptions.Builder<Model1>()
.setQuery(query1, Model1.getDocParser())
.build();
FirestoreRecyclerOptions<Model2> fro2 = new FirestoreRecyclerOptions.Builder<Model2>()
.setQuery(query2, Model2.getDocParser())
.build();
Interfaces enforce behavior of instances, so that references to any object which has that behavior can be passed around in a type-safe way. Static methods on the other hand, don't belong to any particular instance of an object; the class name is essentially just a namespace. If you want to enforce behavior, you will have to create an instance somewhere (or use reflection, if it is absolutely necessary to ensure a class has a particular static method).
Unless this system is going to be opened up for extension, where others can define their own models, I would say ditch the DocParserSupplier interface altogether and call the static methods exactly as you are now, or factor them out into a factory interface + implementation. The factory option is nice because you can replace the production implementation with a fake implementation that returns dummy parsers for tests.
Edit: Doc Parser Factory
public interface DocParserFactory {
SnapshotParser<Model1> getModel1Parser();
SnapshotParser<Model2> getModel2Parser();
...
SnapshotParser<Model1> getModelNParser();
}
...
// The implementation of each getModelXParser method
class DocParserFactoryImpl {
SnapshotParser<Model1> getModel1Parser() {
return docSnapshot -> {
Map<String, Object> data = docSnapshot.getData();
return new Model(data.getOrDefault("name", "John Doe"))};
}
...
}
...
private DocParserFactory docParserFactory;
// You can inject either the real instance (DocParserFactoryImpl) or a
// test instance which returns dummy parsers with predicable results
// when you construct this object.
public ThisObject(DocParserFactory docParserFactory) {
this.docParserFactory = docParserFactory;
}
...
// Your code
public void someMethod() {
...
FirestoreRecyclerOptions<Model1> fro1 = new
FirestoreRecyclerOptions.Builder<Model1>()
.setQuery(query1, docParserFactory.getModel1Parser())
.build();
FirestoreRecyclerOptions<Model2> fro2 = new
FirestoreRecyclerOptions.Builder<Model2>()
.setQuery(query2, docParserFactory.getModel2Parser())
.build();
...
}
It's not so much to do with static or non-static, as it is with the fact that you cannot create an instance of a generic object without passing the type parameter(s) one way or another. In fact, I answered a similar question a few days ago, when somebody wanted to use enums to get the required builder.
In short, you cannot write a method <T extends AbstractBuilder> T builder(final SomeNonGenericObject object) (or, in this case, <T extends AbstractBuilder> T builder()) without passing T in some form. Even though it will make sense at runtime, the compiler can't figure out what generic type to use if you don't tell it which one it is.
In Java 8, you can solve this elegantly with method references. I don't know much about Android, but I believe you're still on Java 6 there, so this wouldn't work.
Anyway, you can have something like the following:
public <T extends AbstractBuilder> T builder(final Supplier<T> object) {
return supplier.get();
}
final Supplier<AbstractBuilder> model1BuilderSupplier = Model1Builder::new;
builder(model1BuilerSupplier)
.setQuery(query1, Model1.getDocParser())
.build();
It's not exactly what you want, but the way you're trying to go about it will not work.

How to add attributes Dynamically for java object?

Having Student Class.
Class Student{
String _name;
....
....
public Student(){
}
}
is there any possibility to add dynamic attributes to Student Object?
without extending the student class.
In short, yes it is possible to modify bytecode at runtime, but it can be extremely messy and it (most likely) isn't the approach you want. However, if you decide to take this approach, I recommend a byte code manipulation library such as ASM.
The better approach would be to use a Map<String, String> for "dynamic" getters and setters, and a Map<String, Callable<Object>> for anything that isn't a getter or setter. Yet, the best approach may be to reconsider why you need dynamic classes altogether.
public class Student {
private Map<String, String> properties = new HashMap<String, String>();
private Map<String, Callable<Object>> callables = new HashMap<String, Callable<Object>>();
....
....
public String getProperty(String key) {
return properties.get(key);
}
public void setProperty(String key, String value) {
properties.put(key, value);
}
public Object call(String key) {
Callable<Object> callable = callables.get(key);
if (callable != null) {
return callable.call();
}
return null;
}
public void define(String key, Callable<Object> callable) {
callables.put(key, callable);
}
}
As a note, you can define void methods with this concept by using Callable and returning null in it.
You could get into bytecode manipulation but that way madness lies (especially for the programmer who has to maintain the code).
Store attributes in a Map<String,String> instead.
Although you can do that with some tricky, and complex way that others have suggested..
But you can sure have your attributes in some data structure(An appropriate one will be a Map).. Since you can modify your existing attributes, so can be done with you Data Structure. You can add more attributes to them.. This will be a better approach..

General Java class design for property with Collection which needs to listen for change

All,
Hopefully a simple question. I am thinking of the best way to implement a class which holds a number of collections and HashMaps where the class needs to know about when they have been modified outside of the class - i.e. added/removed/changed items. Each collection/hashmap needs to be exposed as a public getter in my class at the moment.
So my basic class looks like as follows...
public class MyClass {
protected final HashMap<String, String> _values = new HashMap<String, String>();
protected final ArrayList<MyOtherClass> _other = new ArrayList<MyOtherClass>();
protected final ArrayList<MyOtherClass2> _other2 = new ArrayList<MyOtherClass2>();
// ... implementation
public HashMap<String, String> getValues() {
return _values;
}
public ArrayList<MyOtherClass> getMyOtherClassList() {
return _other;
}
public ArrayList<MyOtherClass2> getMyOtherClassList2() {
return _other2;
}
public String getContent() {
// build the content based on other/other2...
StringBuilder sb = new StringBuilder();
// iterate through both collections to build content...
// ...
return sb.toString();
}
}
public getMyOtherClass {
public String name; // has getter and setter
public String value; // has getter and setter
}
public getMyOtherClass2 {
public String name; // has getter and setter
public String value; // has getter and setter
public String somethingElse; // has getter and setter
}
I want to add a key/value to the _values based on the length of the content i.e.-
_values.add("Length", getContent().length);
So the Length value is dynamic based on what gets added to the _other and _other2.
The problem with this is exposing the _values and _other with public getters is that anything outside the class can modify them. The class will not know if items have been modified.
A couple of solutions I can think of is to make the collection/hashmap readonly - but this throws a runtime exception - if this was the case I'd like the compiler to indicate that they are read-only and throw an exception but I don't know if this is possible.
The other way would be to add a add/remove for each of the collections/maps and update the Length property accordingly - but again, if the values change in the MyOtherClass, MyClass will still not know about it.
Alternatively write my own Hashmap/List/Collection to determine when items are added/removed, and possibly have a property change listener on the getMyOtherClass, getMyOtherClass2.
Any nice solutions to this?
Thanks,
Andez
Overide the map/list implementations and insert a call-back into the add/update/remove methods that triggers an update function on the parent.
Also it's bad form to create references directly to the implementations - this is better (read up on polymorphism for reasoning):
private Map<String,String> myMap = new HashMap<String,String>();
private List<String> myList = new List<String>();
In this case you can make use of some fundamentals of the Observer design pattern to have an Object "watching" the Maps and registering each change is made to them.
Create an object contains a Map and another object that contains a List, so since you have 1 map and 2 lists you'll have 3 of those "Observable" objects. Let's name the classes "ObservableMap" and "ObservableList". You can even create an abstract class "ObservableObject" and extend it with the previously mentioned classes.
These objects won't override the Map/List implementation, they'll only act as a wrapper by wrapping the methods you'll want to track to register the state and derive the call to modify the collection. For example, I'll post some code of the ObservableMap class (I'm instantiating the map with <String,String> but you can use generics here too if it suits you).
public Class ObservableMap extends ObservableObject{
private Map<String,String> map = new LinkedHashMap<String,String>();
private Watcher observer = new Watcher();
//Example of one of the wrapper methods (the other ones are like this one)
public void putObject(String key, String value) {
watcher.notifyPut(); //You can name the method the way you like and even pass
//the new key/value pair to identify what has been added.
map.put(key,value);
}
}
Here, the Watcher class is the one that registers the canges. It can either be a completely new Object (like in this case) or you can make an Interface and implement it in an existing class of yours to be able to set it as a watcher on your Observable objects.
Not 100% sure what you are asking. If you are trying to track changes to attributes to two classes you may wish, as other people have mentioned implement the observer pattern and raise notifications in the set methods. An alternative, that I have used successfully for implementing an undo mechanism is to use aspectJ or some other AOP (Aspect Orientated Programming) tool to intercept the set methods and perform the required notifications/updates that way.
Alternatively define an interface that only provides access to the getXXX operations and return those from your model, that way nothing can change the data.

How to make this part of code scalable,

There is a part in my java code where I am extending a class from a library which I haven't written.
#override
public Object getPropertyValue(Object id) {
if(id.equals(model.PROPERTY_RENAME))
model.setName((String)value);
else if(id.equals(model.PROPERTY_COLOUR))
model.setColor((Color)value);
}
Now in this case how should I modify this code to make it scalable. There would be many more properties like location, dimension, etc. Now this model is instance of an abstract class AbsModel.
So every class implementing the AbsModel would have different properties. So the class architecture should be there, so that this part of code remains unchanged, no matter how many more model classes I add.
It looks like you want to carry out some operation on the model when this method (getPropertyValue) is called. I would create a Map of id onto the interface ModelOperation defined as follows:
public interface ModelOperation {
void operate(Object value);
}
Then the map would be defines as follows:
map.put(model.PROPERTY_RENAME, new RenameOperation(model));
Your extension class would then look like this:
#Override
public Object getPropertyValue(Object id) {
map.get(id).operate(model);
// etc...
}
For example, RenameOperation would be defined like this:
public class RenameOperation implements ModelOperation {
public RenameOperation(Model model) {
// etc...
}
public void operate(Object value) {
model.setName((String)value);
}
}
This allows you to support as many model operations as you like and means you don't have to change the extension class you have to write. The above is just an outline. You could use generics on the ModelOperation implementations to avoid the cast of the value in each one.
I guess reflection is probably the answer here if you can rely on some naming to help direct you.
It's not going to be nice, but the idea would be that you'd have a method that would reflect on the type and look up the appropriate method. The code belwo
public Object setPropertyValue(Object id) {
String className = id.getClass().getSimpleName();
// Hope that the method is called set<CLASS> and takes a single parameter that is the class
Method method = model.class.getMethod("set" + className, id.getClass());
// Invoke the method (TODO deal with all of the exceptions)
method.invoke(model, id);
}
There are multiple ways of doing this -- though it depends on what do you mean by "scalable" (being able to cope with lots of requests per second or being able to cope with lots of properties?):
one way -- if you're going to go down the path you have outlined in your code is to have those properties that are used very often at the top of your if/then/else block -- so their execution path is very short. this would "scale up" well for lots of requests as not too much time is being spent in actually executing the method (in most cases at least!)
another way -- and this scales up well for lots of properties and easiness of maintaining the code but you will take a hit on execution time: have a Map that maps property names to setxxx() method names, then you can use reflection to invoke these methods on the target object (id in your case) on each call. Classes extended your class will only have to provide a getMap() method which will return the mapping name-to-setter method, which can be a static member and initialized on class load.
Store your properties in a Map -- in which case setName() is the same as map.put( PROPERTY_RENAME, value)
Since in Java functions are not first class citizens, the "nice" route would be very awkward: define an enum with one value per each constant above (i.e. for each property), and a virtual method e.g. update(Object value, then override the method in each enum to update the corresponding property. If you can, redefine the constants PROPERTY_RENAME etc. themselves as enums. This still results in code bloat.
The other way is to use reflection. If you can use the same ids as the property names you want to update, you only need to invoke the setter for the property (as illustrated in other answers). Otherwise you may need to introduce a mapping from ids to property names.
A version not using reflection, call the base class's implementation:
public Object getValue(Object id) {
Object ret = super.getValue(id);
if (ret == null) {
// Subclass specific properties
}
return ret;
}
A common way around this is to use reflection like
public Object getValue(IdType id) {
Method getter = model.getClass().getMethod("get" + id);
return getter.invoke(model); // throws Exceptions.
}
OR
public void setValue(IdType id, Object value) {
Method setter = model.getClass().getMethod("set" + id, value.getClass());
setter.invoke(model, value); // throws Exceptions.
}
I solved this issue by creating an interface. So the code is.
public interface IModel
{
public void setProperty(String propertyName);
}
Rest of the classes were
public class HelloModel implements IModel
{
public void setProperty(String propertyName)
{ code for handling the properties goes here ... }
}
So in this case every class has to handle it's own property setters.
Is this the best way to handle abstraction ? I think this model is very scalable ...

Categories

Resources