Avoid duplicate code with numerous Java classes sharing fields - java

I'm working on an application which writes on a NoSQL database (Elasticsearch to be precise) and I have to manage more than a dozen (the number grows with time) different document classes, that is classes with numerous fields, their getters and setters and methods to convert the class to a JSONObject (each field is annotated with #JsonProperty(PROPERTY_NAME) and we use a JSON parser ).
All these classes have some fields and methods in common, which are all contained in a superclass (let us call it DocZero) but they all have their own custom fields, which brings me to the point.
It is true that these fields are custom, but some are shared between different classes in a non-linear way, that is I have my document classes Doc1, ... DocN and I have some sets of fields (around 10 as of right now) shared by them in a very wild way.
Some examples to best convey the situation:
Doc1 contains Set1 to Set5;
Doc2 contains Set1, Set2 and Set5 to Set8;
Doc3 contains Set6 and Set7;
Doc4 contains Set5 and Set7;
Doc5 contains Set1, Set2, Set5 and Set7 to Set10.
Given that I need to get and set these fields and, from time to time, manipulate a document with them, I made interfaces out of the Set#, each containing (abstract) setters and getters.
As such, when I declare a class
public class DocX implements SetA, SetB, SetC
I get reminded to implement the methods and hence add the required fields, but this means that all the classes implementing the same set will need to have the same parameters and the same methods which means that I need to write the same code many times (sometimes more than getter and setter methods).
Adding all the fields to DocZero foregoing the different Doc# classes is a solution which I am not keen on using, since I prefer to distinguish different document types and since this situation is present, in lower magnitude, in another section of the code, with AnotherDocZero, AnotherDoc# and AnotherSet# for which merging cannot be done due to other constraints and for which I would like a potential solution to work too.
I feel like this is one of those situation where multiple inheritance would solve the issue, but unfortunately Java doesn't allow it.
How could I avoid duplication in a situation like this? Have you got any advice to improve my handling of this issue?

If several kinds of fields are often grouped together, that suggests that grouping is a natural part of the domain of your program, and should be represented as such.
So, if you often find this in your classes
int xCoordinate;
int yCoordinate;
You should instead introduce
public final class Point ... {
private final int x;
private final int y;
Point(int x, int y) {
...
}
...
}
then instead of repeating x and y, write
Point position;

I strongly suggest to keep your data classes simple even if it does mean that you will need to repeat many fields definitions - POJOs are definitely easier to maintain and understand how the "result" data object looks like if you have all fields in one place - multilevel inheritance will quickly create a mess
For constraints of having proper getters you should use interfaces as you do. You can even create single interface for every getter and group them in another one like
public interface Set1To5 extends Set1, Set2, Set3, Set4, Set5 {}
For avoid duplication of getters/setters you can use some additional lib like lombok or consider not using getters/setters at all (just make all the fields in your data document classes public - but this one of course is not the option if you need to constraint classes with interfaces)

There is a pattern to explore. I don't know it already exists or there is a specific name for it.
Consider:
Java 8+ interfaces can have default methods. These methods can use other interface methods to define additional / default logic. The class implementing such an interface automatically get these methods, without having to implement them.
Also, a class can implement multiple interfaces.
The above two can be used to have "easy to compose" types in Java.
Example:
Create a base interface that can store/retrieve data. This can be as simple as:
public interface Document {
<T> T get(String key);
void set(String key, Object value);
}
This is the basic capability that will be used by all specific data objects.
Now, define two interfaces that contain nothing but specific field getter/setters using the above interface:
public interface Person extends Document {
default String getName(){
return get("name");
}
default void setName(String name){
set("name", name);
}
}
And another one:
public interface Salaried extends Document {
default double getSalary(){
return get("salary");
}
default void setSalary(double salary){
set("salary", salary);
}
}
Get the idea? This is a simple schema built upon the basic get/set capability. And you might want to define field names as constants in real applications.
But so far, it is all interfaces. It is not linked to something real, like a DB. Hence we must define an implementation to Document that uses a DB storage:
public class DBDoc implements Document {
private final Map<String,Object> data;
public DBDoc(HashMap<String, Object> data) {
this.data = new HashMap<>(data);
}
public DBDoc(){
this.data = new HashMap<>();
}
#Override
#SuppressWarnings("unchecked")
public <T> T get(String key) {
return (T) this.data.get(key);
}
#Override
public void set(String key, Object value) {
this.data.put(key, value);
}
}
We have used a simple map for storage, but it might as well be using a db connection or db specific document to get/set data. This is up to what DB or storage you are using.
Finally, we have the capability to compose types out of these interfaces:
public class Employee extends DBDoc implements Person, Salaried { }
And use them:
public static void main(String[] args) {
Employee employee = new Employee();
employee.setName("Joe");
employee.setSalary(1000.00);
System.out.println(employee.getName());
System.out.println(employee.getSalary());
}

I think default method is an option to go.
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html

Related

How to decrease size of class in DDD to not break the encapsulation?

I'm trying to understand the DDD and I'm encountering some problems. Now I'm refactoring some of domain class N. It has a lot of methods that takes a DTO, validates it and then updates some fields of N. I feel that further it will have much more methods. I think that it's good to preventively extract methods from the N to own classes, a.k.a. Commands. But it means that this commands will have the access to fields of N. Will this refactoring break encapsulation? Is there a way to decrease N's size more safe?
This is what I have
class N {
// Other fields
private String someField;
// Other fields
public void editSomeField(SomeFieldEditCommand command) {
// Some validations
this.someField = command.getSomeField();
}
// Other methods with similar structure
}
interface SomeFieldEditCommand {
String getSomeField();
}
What I'm going to do
class N {
// Other fields
#Setter(Access.PACKAGE)
private String someField;
// Other fields
}
class SomeFieldEditCommand extends AbstractCommand {
private final String someField;
public void accept(N n) {
// Some validations
n.setSomeField(this.getSomeField()); // Does this code breaks encapsulation or it's normal behaviour?
}
}
I feel that further it will have much more methods.
If avoiding proliferation of methods in domain types is your motivation for introducing commands, then be assured that defining methods in entities or aggregate roots is not only normal but is one of the DDD tenets (avoiding anemic domain models). Define intention-revealing public methods in the domain types; pass the values extracted from the DTO to them and do the property settings inside them; keep the property setters private.
But it means that this commands will have the access to fields of N.
Command interface defines an execute method; a concrete command holds reference to a target type (N in your case) and encapsulates some operation on it in the execute method. So the concrete command obviously has coupling with the target class. Still if you want to introduce commands, you may call your domain entity methods from the command's execute method instead of setting properties.

Understanding the Builder/Factory Pattern

I'm trying to clean up some code I have written for reading data. I have two sources of data: a database and a file. Both currently have separate classes and both classes have optional, non common, parameters in the constructors provided (at the moment traditional telescoping constructors).Both classes Implement interface MyData and when I instantiate the objects I always instantiate a MyData object.
I want to merge these classes into a single class and make the instantiation as clean as possible but I can't figure out how. Im certain its a mixture of builder and factory patterns.The user should never have to see the underlying type MyDatabaseData and MyFileData, just MyData. Can someone help me by sketching out a similar example just to set me off in the right direction
Keep the classes separate since they do different things. Combining them will only make a giant mess and violates the Single Responsibility Principle.
If you don't want the users to see the classes, then make the classes package private.
Then you make a new Builder or Factory class that takes parameters and figures out which class to instantiate.
Hope this helps.
A builder pattern would look like this:
MyDatabaseData data = MyDatabaseData.create()
.authenticate("admin", "rumpelstielchen")
.get();
public class MyDatabaseData {
private MyDatabaseData() { }
public static MyDatabaseBuilder create() {
return new MyDatabaseBuilder(new MyDatabaseData());
}
}
public class MyDatabaseBuilder {
private MyDatabaseData data;
MyDatabaseBuilder(MyDatabaseData data) {
this.data = data;
}
public MyDatabaseData get() {
return data; // Do checks and yield the final result
}
public MyDatabaseBuilder authenticate(String user, String password) {
...
return this; // For chaining calls
}
}
Whether to use common base classes/interfaces is a matter of suitability:
public class MyDatabaseBuilder extends MyBuilder<MyDatabaseData>
However you will probably need to do specific things and hence need child classes. Development not necessarily will become easier, maintaining 4 classes with parallel evolutions.

Create Fields and methods dynamically

I want to add new fields(variables) and encapsulating methods for a given class. For example: A class name Student has no any fields like below:
public class Student implements Serializable{
}
then in my application an instance is created;
Student s=new Student();
I want to add new methods which do not exist for student class at the run time.for example: I want to add a field called studentName, and getStudentName() and setStudentName() methods.
Then at the run time the student object will be like this;
public class Student implements Serializable{
private String studentName;
public void setStudentName(..){}
public String getStudentName(){return ...;}
}
In my application objects are written to a text file and all objects of same type do not have all variables. Therefore, I want to add only the required fields to save memory.
Any way is there a way to do this? Any sample code or link?
EDIT: or else can we create a class either and create instances which does not exists ?
EDIT 2: Thanks all of you answered and got many info and ideas. And changed the way to a better path from your suggestions as well
Why not just create a HashMap of values? Much more efficient, and has all the flexibility you're looking for.
public class Student
{
private HashMap<String, String> values;
public Student()
{
this.values = new HashMap<String, String>();
}
public void addValue(String name, String value)
{
values.put(name, value);
}
public String getValue(String name)
{
return values.get(name);
}
}
Why a HashMap?
You said that all objects may have differing values, and you'll be defining those new methods and attributes by a String. Well.. this will achieve that functionality without any horrible bytecode manipulation. For example:
String attrName = "name";
String attrValue = "jim";
Student stu = new Student();
stu.addValue(attrName, attrValue);
At the moment, you've only got the one value in your HashMap. The only overheard you have to face is the HashMap object itself, and two methods, which frankly is a fair trade off for a far tidier solution.
You can use bytecode instrumentation libraries like Javassist or ASM for this purpose. Here is an example of adding a field or method by using Javassist.
While it is possible with bytecode manipulation and such it wouldn't be wise, especially if you intend to do this to "save memory". It's unlikely that you would have so much data that it would make a difference, and if you did, you would store them in a database anyways.
Instead of writing your own HashMap based solution you can use DynaBean and DynaClass: support not only simple properties but also indexed (Array) and mapped (Map).
DynaBean can be introspected to get properties and values so you can dump to file BUT
with this solution you are only "simulating" a bean, your Student class doesn't really contains fields and accessors (you you call Student.getClass().getDeclaredField() you will get an empty array).
If you need to compose a "real" java java.lang.Class Javassist (my preferred choice, I used to resolve a solution similar to your question) or ASM (or CGLIB) are the best choiches.
I dont believe if this is possible in java but I'm sure it will only add to the memory because if you add them dynamically they must be set up beforehand + the code to add them dynamically.
Practically speaking, not in Java. In other languages like Javascript, this is possible.
Java is not a dynamic programming language and so I would not advice to follow that route even if some advance approaches may allow you to do so.
The Java idiom for that scenario would be to store the field values in a (hash) map instead. So you would have a couple of common accessors to set or get all attribute values and in the accessor you would need to indicate the name of the attribute you want to change.
However this solution won't save memory unless the maximum number of attributes is rather large and most object just have values for a small number of such attributes.
public class Entity {
// 5 is an estimate for the number attrs.
private Map<String,Object> attrs = new HashMap<>(5);
public Object getAttribute(String name) { return attrs.get(name); }
public void setAttribute(String name, Object obj) { attrs.put(name,obj); }
}
You could implement some runtime type-checking if you manage meta-data about possible attributes and their value types.

Enforce single-entry collections in single-entry instance of composed object

I have an abstract class that implements an interface. I then have several classes that extends that abstract class that are in turn composed of a hierarchy of some objects plus one or more Lists of objects extending the same abstract class, repeated for some levels. In essence,
public interface Bar
public abstract class BarImpl implements Bar
public class Foo extends BarImpl {
private String value1;
private String value2;
private List<Foo2> fooSubs;
public List<Foo2> getFooSubs() {
return fooSubs;
}
}
public class Foo2 extends BarImpl {
private String value3;
private String value4;
private List<Foo3> fooSubs;
public List<Foo3> getFooSubs() {
return fooSubs;
}
}
...etc...
The data in question is actually X12 healthcare claim data for those who are familiar. I've defined a Loop interface to correspond to the various loops that compose the X12 file.
My issues is this - I need to also be able to describe a single transaction, in theory using the same object or some wrapper on that object, where for some specified depth the size of each list of objects is 1.
My first though is/was to add a boolean singleTransaction to the BarImpl abstract class. Each class extending that would then have a check on the addFoo methods to make sure that the object did not grow beyond the single entry. Before converting to FooSingle I would check as well.
public void addFoo(Foo foo) throws FooException {
if (singleTransaction && fooSubs.size() >= 1)
throw new FooException();
else
fooSubs.add(foo);
}
I would also have to remove the setFoo method, so as to prevent an already-populated List from being assigned. Perhaps just make it final...
Does this seem like a reasonable way to go about this? I could then have a SingleBarImpl class that would verify it had a single path down the hierarchy, filter the boolean down, and could then safely assume that there was only one object-per-list for the specified classes. This could then simplify the access to the hierarchy since I no longer needed to worry about multiple list entires.
This feels very ugly is why I raise the question, and I wasn't quite sure what I should search on for an alternative. So I decided to stop lurking, create an account, and throw this out there. So...any ideas? Am I missing some design pattern that makes this much more elegant?
I am not familiar with X12 healthcare claim data and hence can't properly model the domain, but it sounds like you want to use the GOF composite pattern . A "Leaf" implementation class could easily replace your "singleTransaction" flag

How to remove the dependency on a Java enum's values?

[Mind the gap: I know that the best solution would be to get rid of the enum completely, but that's not an option for today as mentioned in the comments, but it is planned for the (far) future.]
We have two deployment units: frontend and backend. The frontend uses an enum and calls an EJB service at the backend with the enum as a parameter. But the enum changes frequently, so we don't want the backend to know its values.
String constants
A possible solution would be to use String constants insteadof enums, but that would cause a lot of little changes at the frontend. I'm searching a solution, which causes as few changes as possible in the frontend.
Wrapper class
Another solution is the usage of a wrapper class with the same interface as an enum. The enum becomes an wrapper class and the enum values become constants within that wrapper. I had to write some deserialization code to ensure object identity (as enums do), but I don't know if it is a correct solution. What if different classloaders are used?
The wrapper class will implement a Java interface, which will replace the enum in the backend. But will the deserialiaztion code execute in the backend even so?
Example for a wrapper class:
public class Locomotion implements Serializable {
private static final long serialVersionUID = -6359307469030924650L;
public static final List<Locomotion> list = new ArrayList<Locomotion>();
public static final Locomotion CAR = createValue(4654L);
public static final Locomotion CYCLE = createValue(34235656L);
public static final Locomotion FEET = createValue(87687L);
public static final Locomotion createValue(long type) {
Locomotion enumValue = new Locomotion(type);
list.add(enumValue);
return enumValue;
}
private final long ppId;
private Locomotion(long type) {
this.ppId = type;
}
private Object readResolve() throws ObjectStreamException {
for (Locomotion enumValue : list) {
if (this.equals(enumValue)) {
return enumValue;
}
}
throw new InvalidObjectException("Unknown enum value '" + ppId + "'");
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (ppId ^ (ppId >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Locomotion)) {
return false;
}
Locomotion other = (Locomotion) obj;
if (ppId != other.ppId) {
return false;
}
return true;
}
}
Did you already had the same problem? How did you solved it?
Ok, let me see if I understand. You said that
"The frontend uses an enum and calls
an EJB service at the backend with the
enum as a parameter. But the enum
changes frequently, so we don't want
the backend to know its values"
When you say "values" I assume you are referring to the numeric value you pass in the enum constructor and not to the enum constants themselves.
Therefore, this implies that the frontend and the backend will have two different versions of the enum class, but the enum constants in them will be the same.
I am only assuming the communication is via RMI (but this is not entirely clear in your post).
Now, serialization/deserialization of enums works different than with other objects. According to the Java Serialization Specification, when a enum is serialized, only its name is serialized. And when it is deserialized, it is built using the Enum.valueOf(name) method.
So, your original wrapper proposal would not work, because the server, due to stipulated serialization of Enums will never know the actual value of the enums in the client.
Bottom line, if you intend to pass an enum to the server there is no possible way to do what you pretend to do because the values in the frontend will never reach the backend if serialization is implied.
If RMI is implied, a good solution would be to use code mobility, this way you could place the problematic class in a repository accessible to both, server and client, and when the frontend developers change the class definition, you can publish the class in the repository and the server can get it from there.
See this article about dynamic code downloading using code base property in RMI
http://download.oracle.com/javase/6/docs/technotes/guides/rmi/codebase.html
Another possible solution is that you could stop using a Java Enum and use Java class with final constants, as we used to do in the old days before enums, and that way you can ensure that its values will be properly serialized when they are are sent to the backend.
Somewhat like this
public class Fruit implements Serializable{
private static final long serialVersionUID = 1L;
public final Fruit ORANGE = new Fruit("orange");
public final Fruit LEMON = new Fruit("lemon");
private String name;
private Fruit(String name){
this.name = name;
}
}
This way you can be in full control of what happens upon deserialization and your wrapper pattern might work this way.
This type of construction cannot substitute an enum completely, for instance, it cannot be used in switch statements. But, if this is an issue, you could use this object as the parameter sent to the server, and let the server rebuild the enum out of it with its version of the enum class.
Your enum, therefore, could have two new methods, one to build Java instances out of the enum itself:
public static Fruit toFruit(FruitEnum enum);
public FruitEnum valueOf(Fruit fruit);
And you can use those to convert back and forth versions of the parameter for the server.
It's an odd request, as i would think the server should know about the values of what is going into the database, but ok, i'll play along. Perhaps you could do this
public enum Giant {Fee, Fi, Fo, Fum};
public void client() {
Giant giant = Giant.Fee;
server(giant);
}
public void server(Enum e) {
String valueForDB = e.name();
//or perhaps
String valueForDB = e.toString();
}
For data transfer between frontend and backend both need to use the same class versions because of possible serialization during marshalling parameters. So again they have to know exactly the same enums or whatever other classes you try to use. Switching enums to something different won't work either. You have to set on a known class identiy for both.
So if the server should do actions based on some kind of processing/calculating the values of the parameters use strings or whatever other non-changing class you decide on and put your values inside: string of characters, array of numbers or whatever.
So if you put your database id inside the wrapper object the server will be able to get the objects out of the database. But still - they both need exact the same version of the wrapper class in their classpaths.
Okay, I can't be too exact because I don't see your code but in my experience something that changes like that should be external data, not enums.
What I almost always find is that if I externalize the information that was in the enums, then I have to externalize a few other pieces as well, but after doing it all I end up factoring away a LOT of code.
Any time you actually use the values of an enum you are almost certainly writing duplicate code. What I mean is that if you have enums like "HEARTS", "DIAMONDS"...
The ONLY way they can be used in your code is in something like a switch statement:
switch(card.suit)
case Suit.HEARTS:
load_graphic(Suit.HEARTS);
// or better yet:
Suit.HEARTS.loadGraphic();
break;
case Suit.SPADES:
Suit.SPADES.loadGraphic();
...
Now, this is obviously stupid but I made the stupid constraint to say that you USED the values in the code. My assertion is that if you don't USE the values you don't need an enum--Let's not use the values in code and see:
card.suit.loadGraphic();
Wow, all gone. But suddenly, the entire point of using an enum is gone--instead you get rid of the whole class preload a "Suit" factory with 4 instances from a text file with strings like "Heart.png" and "Spade.png".
Nearly every time I use enums I end up factoring them out like this.
I'm not saying there isn't any code that can benefit from enums--but the better that I get at factoring code and externalizing data, the less I can imagine really needing them.

Categories