After reading through nested classes, nested lists, and mapping, I'm still having trouble deciding the proper method to use and even still, how to implement those three methods.
Objective: tracking statistics of multiple services up time from a log file. Each service status change is on one line and contains the Name, the oldStatus, newStatus, and timeChanged
In the end, I'd like to see the time between these lines but for now I'm simply trying to organize the data properly.
Currently, I'm going down the road of using a class and here is the building of it:
public class Services {
private List<String> AllServices = new ArrayList<String>();
// Initial thought of adding another list here, containing
// the variables, but how would I associate that to the
// service above?
private List<String> ServiceStatus;
public boolean AddService(String name) {
if (!AllServices.contains(name)) {
AllServices.add(name);
return true;
}
return false;
}
public List<String> GetServices() {
return AllServices;
}
}
That is all find and good. As the parser discovers a new service, it adds it to the list so there aren't duplicates. Then, I moved on to adding each time it find a service status has changed. I can't figure out how, for each service, to store that data.
I guess I could liken it to using a database with the unique identifier being the service name, holding records for each time the status changes, what it changed to, and the time. Once I get that down, I can start comparing the times between.
Initial thought of adding another list here, containing the variables, but how would I associate that to each service?
I considered arrays, but in Java they seem rather static, as in having to resize them to add more data. I've since forgotten the work around for this in PHP, but from my limited past experience I recall being able to build up and use arrays such as:
statusChanged = myServices["TheService"][i][date];
statusChangedTo = myServices["TheService"][i][new_status];
statusChangedTo = myServices["OtherService"][i][date];
statusChangedTo = myServices["OtherService"][i][new_status];
AllServices
|- TheService
| |- TimeDate
| | - New Status
| | - Old Status
|- OtherService
|- TimeDate
| - New Status
| - Old Status
Which lead me down the path of using extended Classes. I could have Services and also Service. Services would result in just having a List of services, but then how does Service again associate it's underlying variables to specific services listed in the parent Services class?
Again, I feel like I'm overthinking this after reading too many examples that are similar but not to what I'm trying to accomplish. Or, I'm just completely off the wall entirely and there could be a far better method.
I suggest to use any DB to persist logged events. It is preferrable solution in case of many services with many events.
Otherwise, I provide a few steps for storing them in memory:
First of all, you should to divide data by name of service. Use Map<K,V> for it.
Secondly, I suggest you to combine oldStatus, newStatus and timeChanged into ServiceEvent class:
public class ServiceEvent {
private final String oldStatus;
private final String newStatus;
private final DateTime timeChanged;
// methods...
}
It is convinient to order events by timeChanged with Comparator in case of unordered sequence of events:
public class ServiceEventComparator implements Comparator<ServiceEvent> {
#Override
public int compare(ServiceEvent e1, ServiceEvent e2) {
return e1.getTimeChanged().compareTo(e2.getTimeChanged());
}
}
Thus, your ServiceEventRepository can be like this:
public class ServiceEventRepository {
private Map<String, SortedSet<ServiceEvent>> storage = new HashMap<>();
public void addEvent(String service, ServiceEvent event) {
SortedSet<ServiceEvent> events = storage.get(service);
if (events == null) {
events = new TreeSet<ServiceEvent>(new ServiceEventComparator());
storage.put(service, events);
}
events.add(event);
}
}
Use simple List<ServiceEvent> if sequence of events has natural order.
Note that the ServiceEventRepository above is not thread safe.
Related
This is more of a "Design" or "Conception" sort of question.
So I have a simple problem; I want to print some workers info in an Excel sheet.
But I want to do it in a way that is easy to change in the future, let me explain : for now, people just want to see last name, first name and address in that excel table. But, what if all of a sudden they want more ? Or less ? How to add or remove a column (that actually refers to a field in the Worker class) hassle free ?
In a simple picutre, I want a simple system to go from this (these would be excel sheets) :
| first name | age | job |
-----------------------------------
| joe | 26 | developer |
| mary | 25 | tester |
to this :
| first name | last name | status | adress |
---------------------------------------------------------
| joe | johnson | employee | 8 sun street |
| mary | hoover | bos | 6 moon street |
So my class is Worker, I thought about making a class that is called WorkerTabular that would have a List of java.lang.reflect.Field references in it, and then I can check, but I don't want to break the encapsulation, that would kind of defeat the purpose of making an "easily variable system", if all of a sudden we tie to the implementation and oversee getters. So instead I thought of storing the references to the getter methods in this List of columns. But how would I call that function reference I stored on an instance of Worker?
Something like (using the builder pattern) WorkerTabular().addColumn(Worker::getName).addColumn(Worker::getHiringDate) and then, in a third class like ExcelMaker do something like worker.call(Worker::getName) to get the name.
I want to keep things as segregated as possible to make a truly reusable thing, by leaving the Worker Entity untouched, encapsulating the tabular data we want in the WorkerTabular, and the actual work of making the Excel stuffs in the ExcelMaker class.
Am I missing a well known pattern to do all this ? After all, making a kind of "variable excel sheet" must not be a new problem.
In other languages like Javascript, I can kind of see how that would be done, WorkerTabular would be made with that builder pattern just that it's a List of Strings, and then in ExcelMaker we would just do worker[listElement] while iterating on the list of attributes we chose to be in the Excel sheet. But in Java, I can't really see a clean and "Javaic" way to do it.
I'm sorry if I'm asking a stupid question.
EDIT 1 :
Thanks to Justin Albano for his nice answer :).
You really nailed it I think with the usage of the interface, even the fact that not every field is a String can be handled in the Implementation of TableEntry, by doing the conversion there (Dates to Strings, Ints to Strings, etc). There is a bit of coupling between TableEntry and Worker, but it's kept there and TableBuilder can really just concentrate of it's job of iterating over the List of Strings and build the Excel file.
I'm having a bit of trouble figuring out how to add a "columns titles" line to the TableBuilder, but I guess I'll just do it like this :
class TableBuilder {
List<String> columnTitles;
String tableTitle;
bytes[] build(List<TableEntry> lte) {
// make first row, make title & iterate over entries
// then do miscellaneous things like set the correct merged region for title, etc
}
}
And initialize those fields with a static factory or builder.
Actually this problem arose :
there are two types of Workers, and they have two fields : email and work_email.
A type of worker has both, and the other type has only work_email. So with my implementation I'm screwed ! I would have to put BOTH fields in the Excel table,
and one would be empty for the other type of worker, and people would complain !
Or I would need to split the function generating the Excel file in two thus duplicating a lot of code, or handle this little weird case in the function making it really ugly.
With the implementation with Entry interface to represent data, I can get around this easy ! I get the feeling that it's a bit "overengineered" and certainly my colleagues won't like stumbling through this implementation I think (the codebase is more of a "straight to the point and ugly don't matter" kind of thing), but it's also very clean I feel.
Moreover, the class TableBuilder could build an excel file for any Thing, as long as an implementation class of ThingEntry has been made. That's pretty sweet !
Maybe the only real "issue" I see with it is that 2n objects need to be created now, versus just the n of the 'ugly' implementation. But I feel that in 2018 that's not too big of an issue, right ?
A simple way to allow the internal representation of Worker to vary independently of the tabular representation of the Worker is to create a separate class for its representation. For example, given the following definition of Worker
public class Worker {
private final String firstName;
private final int age;
private final String job;
public Worker(String firstName, int age, String job) {
this.firstName = firstName;
this.age = age;
this.job = job;
}
public String getFirstName() {
return firstName;
}
public String getAge() {
return age;
}
public String getJob() {
return job;
}
}
the following wrapper can be created:
public interface TableEntry {
public List<String> getColumnValues();
}
public class WorkerTableEntry implements TableEntry {
private final Worker worker;
public WorkerEntry(Worker worker) {
this.worker = worker;
}
#Override
public List<String> getColumnValues() {
List<String> columns = new ArrayList<>();
columns.add(worker.getFirstName());
columns.add(String.valueOf(worker.getAge()));
columns.add(worker.getJob());
return columns;
}
}
This would now allow another class, TableBuilder to depend only on the TableEntry interface, not the internals of Worker:
public class TableBuilder {
public String buildTable(List<TableEntry> entries) {
// Print header
for (TableEntry entry: entries) {
List<String> columns = entry.getColumnValues();
// Print each column
}
}
}
Then the TableBuilder can be called as follows:
List<Worker> workers = ...
List<TableEntry> entries = new ArrayList<>();
for (Worker worker: workers) {
entries.add(new WorkerTableEntry(worker));
}
TableBuilder builder = new TableBulder();
builder.buildTable(entries);
This ensures that if the fields or methods of Worker change, its representation in the table does not necessarily change; and vice-versa, if the representation in the table needs to change, that the Worker class does not necessarily need to change (the two are independent). If other tables need to be built, you can simply create more implementations of TableEntry and reuse the TableBuilder class.
If you wanted to store the getters of the Worker class as the means of building the table, you can do so, although doing so is a bit more complicated. At its most basic level, the getters are Supplier<String> objects, meaning that take no arguments but produce a single String value. For example, you can develop a VariableTableEntry in the following manner:
public class VariableTableEntry {
private List<Supplier<String>> columnSuppliers;
public void addColumn(Supplier<String> supplier) {
columnSuppliers.add(supplier);
}
public String getRow() {
for (Supplier<String> columnSupplier: columnSuppliers) {
String columnValue = columnSupplier.get();
// Print each column
}
}
}
The difficult part is that not every getter will return a String. Some, like getAge(), will return an int. To be able to print those getter references as a String, a conversion would have to be performed (this method would be present in the VariableTableEntry class):
public void addIntColumn(Supplier<Integer> supplier) {
addColumn(() -> String.valueOf(supplier.get()));
}
This essential just wraps the supplied getter in a lambda expression that returns a String instead of an Integer/int. This process would be repeated for each of the other primitive values. Any Object (such as Worker) can be handled by deferring to toString:
public void addObjectColumn(Supplier<Object> supplier) {
addColumn(() -> supplier.get().toString());
}
If I have understood correctly, then Worker is your POJO and you are trying to create the list of POJOs and dumping in the excel sheet..So, what's the issue if person can add/remove the attributes in that bean class and corresponding getters/setters?
I am sorry for the vague question. I am not sure what I'm looking for here.
I have a Java class, let's call it Bar. In that class is an instance variable, let's call it foo. foo is a String.
foo cannot just have any value. There is a long list of strings, and foo must be one of them.
Then, for each of those strings in the list I would like the possibility to set some extra conditions as to whether that specific foo can belong in that specific type of Bar (depending on other instance variables in that same Bar).
What approach should I take here? Obviously, I could put the list of strings in a static class somewhere and upon calling setFoo(String s) check whether s is in that list. But that would not allow me to check for extra conditions - or I would need to put all that logic for every value of foo in the same method, which would get ugly quickly.
Is the solution to make several hundred classes for every possible value of foo and insert in each the respective (often trivial) logic to determine what types of Bar it fits? That doesn't sound right either.
What approach should I take here?
Here's a more concrete example, to make it more clear what I am looking for. Say there is a Furniture class, with a variable material, which can be lots of things, anything from mahogany to plywood. But there is another variable, upholstery, and you can make furniture containing cotton of plywood but not oak; satin furniture of oak but not walnut; other types of fabric go well with any material; et cetera.
I wouldn't suggest creating multiple classes/templates for such a big use case. This is very opinion based but I'll take a shot at answering as best as I can.
In such a case where your options can be numerous and you want to keep a maintainable code base, the best solution is to separate the values and the logic. I recommend that you store your foo values in a database. At the same time, keep your client code as clean and small as possible. So that it doesn't need to filter through the data to figure out which data is valid. You want to minimize dependency to data in your code. Think of it this way: tomorrow you might need to add a new material to your material list. Do you want to modify all your code for that? Or do you want to just add it to your database and everything magically works? Obviously the latter is a better option. Here is an example on how to design such a system. Of course, this can vary based on your use case or variables but it is a good guideline. The basic rule of thumb is: your code should have as little dependency to data as possible.
Let's say you want to create a Bar which has to have a certain foo. In this case, I would create a database for BARS which contains all the possible Bars. Example:
ID NAME FOO
1 Door 1,4,10
I will also create a database FOOS which contains the details of each foo. For example:
ID NAME PROPERTY1 PROPERTY2 ...
1 Oak Brown Soft
When you create a Bar:
Bar door = new Bar(Bar.DOOR);
in the constructor you would go to the BARS table and query the foos. Then you would query the FOOS table and load all the material and assign them to the field inside your new object.
This way whenever you create a Bar the material can be changed and loaded from DB without changing any code. You can add as many types of Bar as you can and change material properties as you goo. Your client code however doesn't change much.
You might ask why do we create a database for FOOS and refer to it's ids in the BARS table? This way, you can modify the properties of each foo as much as you want. Also you can share foos between Bars and vice versa but you only need to change the db once. cross referencing becomes a breeze. I hope this example explains the idea clearly.
You say:
Is the solution to make several hundred classes for every possible
value of foo and insert in each the respective (often trivial) logic
to determine what types of Bar it fits? That doesn't sound right
either.
Why not have separate classes for each type of Foo? Unless you need to define new types of Foo without changing the code you can model them as plain Java classes. You can go with enums as well but it does not really give you any advantage since you still need to update the enum when adding a new type of Foo.
In any case here is type safe approach that guarantees compile time checking of your rules:
public static interface Material{}
public static interface Upholstery{}
public static class Oak implements Material{}
public static class Plywood implements Material{}
public static class Cotton implements Upholstery{}
public static class Satin implements Upholstery{}
public static class Furniture<M extends Material, U extends Upholstery>{
private M matrerial = null;
private U upholstery = null;
public Furniture(M matrerial, U upholstery){
this.matrerial = matrerial;
this.upholstery = upholstery;
}
public M getMatrerial() {
return matrerial;
}
public U getUpholstery() {
return upholstery;
}
}
public static Furniture<Plywood, Cotton> cottonFurnitureWithPlywood(Plywood plywood, Cotton cotton){
return new Furniture<>(plywood, cotton);
}
public static Furniture<Oak, Satin> satinFurnitureWithOak(Oak oak, Satin satin){
return new Furniture<>(oak, satin);
}
It depends on what you really want to achieve. Creating objects and passing them around will not magically solve your domain-specific problems.
If you cannot think of any real behavior to add to your objects (except the validation), then it might make more sense to just store your data and read them into memory whenever you want. Even treat rules as data.
Here is an example:
public class Furniture {
String name;
Material material;
Upholstery upholstery;
//getters, setters, other behavior
public Furniture(String name, Material m, Upholstery u) {
//Read rule files from memory or disk and do all the checks
//Do not instantiate if validation does not pass
this.name = name;
material = m;
upholstery = u;
}
}
To specify rules, you will then create three plain text files (e.g. using csv format). File 1 will contain valid values for material, file 2 will contain valid values for upholstery, and file 3 will have a matrix format like the following:
upholstery\material plywood mahogany oak
cotton 1 0 1
satin 0 1 0
to check if a material goes with an upholstery or not, just check the corresponding row and column.
Alternatively, if you have lots of data, you can opt for a database system along with an ORM. Rule tables then can be join tables and come with extra nice features a DBMS may provide (like easy checking for duplicate values). The validation table could look something like:
MaterialID UpholsteryID Compatability_Score
plywood cotton 1
oak satin 0
The advantage of using this approach is that you quickly get a working application and you can decide what to do as you add new behavior to your application. And even if it gets way more complex in the future (new rules, new data types, etc) you can use something like the repository pattern to keep your data and business logic decoupled.
Notes about Enums:
Although the solution suggested by #Igwe Kalu solves the specific case described in the question, it is not scalable. What if you want to find what material goes with a given upholstery (the reverse case)? You will need to create another enum which does not add anything meaningful to the program, or add complex logic to your application.
This is a more detailed description of the idea I threw out there in the comment:
Keep Furniture a POJO, i.e., just hold the data, no behavior or rules implemented in it.
Implement the rules in separate classes, something along the lines of:
interface FurnitureRule {
void validate(Furniture furniture) throws FurnitureRuleException;
}
class ValidMaterialRule implements FurnitureRule {
// this you can load in whatever way suitable in your architecture -
// from enums, DB, an XML file, a JSON file, or inject via Spring, etc.
private Set<String> validMaterialNames;
#Overload
void validate(Furniture furniture) throws FurnitureRuleException {
if (!validMaterialNames.contains(furniture.getMaterial()))
throws new FurnitureRuleException("Invalid material " + furniture.getMaterial());
}
}
class UpholsteryRule implements FurnitureRule {
// Again however suitable to implement/config this
private Map<String, Set<String>> validMaterialsPerUpholstery;
#Overload
void validate(Furniture furniture) throws FurnitureRuleException {
Set<String> validMaterialNames = validMaterialsPerUpholstery.get(furniture.getUpholstery();
if (validMaterialNames != null && !validMaterialNames.contains(furniture.getMaterial()))
throws new FurnitureRuleException("Invalid material " + furniture.getMaterial() + " for upholstery " + furniture.getUpholstery());
}
}
// and more complex rules if you need to
Then have some service along the lines of FurnitureManager. It's the "gatekeeper" for all Furniture creation/updates:
class FurnitureManager {
// configure these via e.g. Spring.
private List<FurnitureRule> rules;
public void updateFurniture(Furniture furniture) throws FurnitureRuleException {
rules.forEach(rule -> rule.validate(furniture))
// proceed to persist `furniture` in the database or whatever else you do with a valid piece of furniture.
}
}
material should be of type Enum.
public enum Material {
MAHOGANY,
TEAK,
OAK,
...
}
Furthermore you can have a validator for Furniture that contains the logic which types of Furniture make sense, and then call that validator in every method that can change the material or upholstery variable (typically only your setters).
public class Furniture {
private Material material;
private Upholstery upholstery; //Could also be String depending on your needs of course
public void setMaterial(Material material) {
if (FurnitureValidator.isValidCombination(material, this.upholstery)) {
this.material = material;
}
}
...
private static class FurnitureValidator {
private static boolean isValidCombination(Material material, Upholstery upholstery) {
switch(material) {
case MAHOGANY: return upholstery != Upholstery.COTTON;
break;
//and so on
}
}
}
}
We often are oblivious of the power inherent in enum types. The Java™ Tutorials clearly states "you should use enum types any time you need to represent a fixed set of constants."
How do you simply make the best of enum in resolving the challenge you presented? - Here goes:
public enum Material {
MAHOGANY( "satin", "velvet" ),
PLYWOOD( "leather" ),
// possibly many other materials and their matching fabrics...
OAK( "some other fabric - 0" ),
WALNUT( "some other fabric - 0", "some other fabric - 1" );
private final String[] listOfSuitingFabrics;
Material( String... fabrics ) {
this.listOfSuitingFabrics = fabrics;
}
String[] getListOfSuitingFabrics() {
return Arrays.copyOf( listOfSuitingFabrics );
}
public String toString() {
return name().substring( 0, 1 ) + name().substring( 1 );
}
}
Let's test it:
public class TestMaterial {
for ( Material material : Material.values() ) {
System.out.println( material.toString() + " go well with " + material.getListOfSuitingFabrics() );
}
}
Probably the approach I'd use (because it involves the least amount of code and it's reasonably fast) is to "flatten" the hierarchical logic into a one-dimensional Set of allowed value combinations. Then when setting one of the fields, validate that the proposed new combination is valid. I'd probably just use a Set of concatenated Strings for simplicity. For the example you give above, something like this:
class Furniture {
private String wood;
private String upholstery;
/**
* Set of all acceptable values, with each combination as a String.
* Example value: "plywood:cotton"
*/
private static final Set<String> allowed = new HashSet<>();
/**
* Load allowed values in initializer.
*
* TODO: load allowed values from DB or config file
* instead of hard-wiring.
*/
static {
allowed.add("plywood:cotton");
...
}
public void setWood(String wood) {
if (!allowed.contains(wood + ":" + this.upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.wood = wood;
}
public void setUpholstery(String upholstery) {
if (!allowed.contains(this.wood + ":" + upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.upholstery = upholstery;
}
public void setMaterials(String wood, String upholstery) {
if (!allowed.contains(wood + ":" + upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.wood = wood;
this.upholstery = upholstery;
}
// getters
...
}
The disadvantage of this approach compared to other answers is that there is no compile-time type checking. For example, if you try to set the wood to plywoo instead of plywood you won’t know about your error until runtime. In practice this disadvantage is negligible since presumably the options will be chosen by a user through a UI (or through some other means), so you won’t know what they are until runtime anyway. Plus the big advantage is that the code will never have to be changed so long as you’re willing to maintain a list of allowed combinations externally. As someone with 30 years of development experience, take my word for it that this approach is far more maintainable.
With the above code, you'll need to use setMaterials before using setWood or setUpholstery, since the other field will still be null and therefore not an allowed combination. You can initialize the class's fields with default materials to avoid this if you want.
Is there a design or development pattern where we deal with making updates to a copy of the actual data and applying the diff to the original reference if needed?
If not, what is the best way of designing such models?
What I think I should do:
I should probably use an enum mode to indicate whether the model is being used in 'Update direct reference mode' OR 'Update only a copy mode'
Update the setters and getters of data to reference the actualState or the temporaryState as per what mode is the model being used in.
Have the setter method for mode to create a copy of the actual data and store it in a temporary state. If the mode is updated to update direct reference, clear out the temporaryState
Create a method for applying the changes from temporaryState to the actualState. This method shall also clear out the temporary state from memory.
In code:
enum InsertionMode {
UPDATE_DIRECT, UPDATE_COPY
}
class Store {
private Data actualState;
private Data temporaryState;
private InsertionMode mode;
private void resetTemporaryState() {
....
}
private void initTemporaryState() {
this.temporaryState = copy(actualState);
}
private commitTemporaryState() {
this.actualState = this.temporaryState;
this.resetTemporaryState();
}
public Data setInsertionMode(InsertionMode mode) {
if (this.mode != mode) {
InsertionMode previousMode = this.mode;
this.mode = mode;
if (previousMode == InsertionMode.UPDATE_COPY) {
this.resetTemporaryState();
}
if (this.mode == InsertionMode.UPDATE_COPY) {
this.initTemporaryState();
}
}
}
public void commit() {
if (this.mode == InsertionMode.UPDATE_COPY) {
this.commitTemporaryState();
}
}
public void abort() {
if (this.mode == InsertionMode.UPDATE_COPY) {
this.resetTemporaryState();
this.setInsertionMode(InsertionMode.UPDATE_DIRECT);
}
}
...
}
The given code is "okay", as it will support your requirements.
But: updating objects is a simple approach, and is easy to implement. But depending on your context, you do things really differently in 2017.
Instead of having one mutable object that changes state, you could instead go for immutable objects. State becomes a sequence of such objects.
Reaching a new state means adding a newly created object at the end of the sequence, cancel means to go with the old, unchanged sequence. This approach is the base for blockchain applications; but it can be scaled down to a smaller context as well - just by looking at its core aspect: you never change state by changing existing objects, but by creating new objects. Of course, this needs a lot of thought; you don't want to blindly duplicate everything; you might more be looking having "delta" objects (that represent individual changes) and "views" that show aggregations of deltas.
Beyond that: you might want to read about CQRS versus CRUD (for example this).
We're setting up a DB with an object model for safes that have bill readers inside to put the bills in. This safe is stored in the Unit class and that unit has a list of placeholders for, let's say, 3 components. Components can change over time, but placeholders will stay connected to the same safe. So this unit has 3 placeholders with identifiers like 'left reader', 'right reader' and 'printer'. The actual component inside such a placeholder has the product type (for instance Mei reader ... or JCM reader ...) and a serial number.
Now, as the unit itself will be requested from the server side quite often as it is shown in one or more (pages of) portals (to see it's own serial number, location, how much money is inside, which users are allowed to log on to this safe, etc.) and components need not be known most of the time we want to lazily load them. The unit itself needs to know it's actual components (configuration) with serial numbers for components to be able to know / tell the back end when a component is exchanged during a servicing by a mechanic.
There is an intermediate table (placeholdercomponents) with placeholder FK, component FK and a datetime placed and a datetime removed.
Right now there is a Unit class that contains, besides a lot else, this:
#OneToMany(mappedBy = "unit", fetch = FetchType.EAGER)
private List<Placeholder> placeholders = new ArrayList<>();
#XmlElementWrapper(name = "Placeholders")
#XmlElement(name = "Placeholder")
public final List<Placeholder> getPlaceholders() {
return placeholders;
}
public final void setPlaceholders(List<Placeholder> pPlaceholders) {
placeholders = pPlaceholders;
}
The placeholder class has this:
#OneToMany(mappedBy = "placeholder", fetch = FetchType.LAZY)
private List<PlaceholderComponent> placeholderComponents;
#XmlTransient
public List<PlaceholderComponent> getPlaceholderComponents() {
if (placeholderComponents == null)
placeholderComponents = new ArrayList<PlaceholderComponent>();
return placeholderComponents;
}
public void setOrganizationUnits(List<PlaceholderComponent> pPlaceholderComponents) {
placeholderComponents = pPlaceholderComponents;
}
#XmlElement(name = "Component")
public Component getCurrentComponent() {
if (placeholderComponents == null) {
return null;
} else {
PlaceholderComponent placeComp = placeholderComponents.stream()
.filter(pc -> pc.getDateTimeRemoved() == null)
.findFirst()
.orElse(null);
if (placeComp == null) {
return null;
} else {
return placeComp.getComponent();
}
}
}
And in the service there should be two possible calls getUnit & getUnitWithComponents. Now, if I remove the #XmlElement(name = "Component") annotation above getCurrentComponent() and do nothing with the placeholderComponents inside the getUnit call it works as expected, but getUnitWithComponents doesn't work (it works, but doesn't return the components inside the placeholders). When I leave the annotation getUnitWithComponents works as expected, but getUnit gives an error about not being able to lazily load the placeholderComponents as, apparently, JAXB wants to build the Component element even though the whole list isn't called in the service and therefore not loaded.
I can think of 3 possible 'solutions' working around this:
Remove the getCurrentComponent and make a separate call for retrieving the current component in a placeholder which would send a single component XML back
Make two different objects for Placeholder while both are for the same DB-table, using the one for getUnit (where the Component annotation isn't present) and the other for getUnitWithComponents (where the Component annotation is present).
Another option would be splitting into DAO's and DTO's as there might be more of those situations coming, but that splitting would take quite some time by now.
So the main question is: is there a way to get the components inside the unit XML for some calls and leave them out for most of the calls without a workaround? And if not, what solution would you chose? 1, 2, 3 or another one?
I'm trying to merge these three objects into a single complex object:
public class Person {
private String name;
private List<Event> events;
// getters and setters
}
public class Event {
private String name;
private List<Gift> gifts;
// getters and setters
}
public class Gift {
private String name;
private String recipient;// the name of the person
private String eventName;
// getters and setters
}
My goal is to save the Person object in MongoDB using Morphia and this how I want my document laid out. I've created a document builder, of sorts, that combines lists of each object. Each Person gets a list of all Events, but can only receive specific Gifts. While my document builder does create a document that Morphia can persist, only the Gifts of that last recipient (sort order) are inserted into the Events for all Persons. Though for the correct Events.
public void merge() {
for (Person person : listOfPersons) {
for (Event event : listOfEvents) {
// somePersonsGifts: a sublist of gifts based on Event and Person.
List<Gift> somePersonsGifts = new ArrayList<Gift>();
for (Gift gift : listOfGifts) {
if (person.getName().equals(gift.getRecipient()) && gift.getEventName().equals(event.getName())) {
somePersonsGifts.add(gift);
}
}
event.setGifts(somePersonsGifts);
}
person.setEvents(listOfEvents)
}
}
If I modify the code slightly to process one person at a time by removing the outer loop and having the method take an argument for specific index of the Persons list:
public void merge(int p) {
Person person = listOfPersons.get(p);
//...and so on
I get one complete Person object with the correct gifts. If try to feed the this modified version into a loop, the problem comes back. I've tried using regular for-loops and synchronized collections. I've tried using Google Guava's ImmutableArrayList and still no luck. I know the problem is that I'm changing the lists while accessing them but I can't find anyway around it. I wrote a DAO that uses the MongoDB driver directly and it works properly, but it's a lot more code and quite ugly. I really want this approach to work, the answer is in front of me but I just can't see it. Any help would be greatly appreciated.
Here is your problem:
List<Gift> somePersonsGifts = new ArrayList<Gift>();
....
event.setGifts(somePersonsGifts);
You add the gifts only for one person; if you want to aggregate all the gifts into the event, re-use the existing list.
I don't know anything about MongoDB or Morphia but I suspect the problem is your use of the setters event.setGifts(somePersonsGifts) and person.setEvents(events). Your code does not seem to merge the existing gift and event lists with the ones you are calculating further in the loop, which is how you would want it to behave (if I understand the question correctly).
You should retrieve the allready existing gift list (and event list too) instead of overwriting them with empty new ones.
I don't know if the method merge() is inside the list but I assume that since you are using the list events here
person.setEvents(events);
Maybe you meant
person.setEvents(listOfEvents)
Notice that you are adding all the events to each person. If all the persons went to all the events, it is unnecessary to have the events inside the person.