I've got a pretty general question.
For my work I have to implement a demonstrator application using MongoDB, Java and JavaFX (and yWorks). So since I - unfortunately - have to work alone on this and there is not a huge amount of know-how in our company, all I did was studying and learning these technologies for myself.
And since we don't want to have a server application there is only MongoDB as a service and the client working on the data. (This is okay, since its only a demonstrator). But im kind of confused.
Implementing pojo classes to store and load from the database and implementing gui model classes with the exact same properties but using "SimpleStringProperty" by JavaFX led to the - in my opinion - weird fact, that i have two semantically identic model classes that I have to implement some kind of Observer/Observable-Pattern to propagate changes from the ViewModels to the POJOS and vice versa.
There must be a more elegant way to do this, right?
Any ideas on this?
Some visualisation:
Analyse
Just the analyse, skip to the proposition if you dont want details
The question to duplicate or not class model definition is an architectural choice, but theses 2 solutions are possible and acceptable:
Use your model bean in controller and Screen
Duplicate all your classes with helpers method from/to for the conversions.
Since the duplication is possible but trivial, I will only describe how to use directly models, there are still another 2 solutions:
1.1 Just manually bind your attributes (the simpler but not the more elegant)
Create Observable SimpleStringProperty ... on the fly when binding read-only, or use Helpers to add listener on screen observable to call regular setter when a value is modifiable
1.2. Make your data framework use getters/setters and not fields: in most case you can configure it (that's the case for hibernate) So if mongodb can serialize/deserialize objects using method and not field, It will be possible
I suppose here that you use standard javaFX bean with 3 accessor on each attributes: get,set,property.
Proposition
Sorry for this big intro, here is a proposed solution using Jackson.
First It is aparently possible to use mongodb with Jackson:Efficient POJO mapping to/from Java Mongo DBObject using Jackson
Then here is an example code of javaFX Bean with jackson:
#JsonAutoDetect(fieldVisibility = Visibility.NONE, getterVisibility = Visibility.PUBLIC_ONLY, setterVisibility = Visibility.PUBLIC_ONLY)
public class MyBean {
private final StringProperty label = new SimpleStringProperty();
public final StringProperty labelProperty() {
return this.label;
}
public final String getLabel() {
return this.labelProperty().get();
}
public final void setLabel(final String label) {
this.labelProperty().set(label);
}
}
You are using morphia, you have to check if this is possible.
Side note:
I'm asking a similar question about non duplication of object on the link below (I am in a 3 tier not 2 tier, but still duplication problem), the usual solution for instance is still the duplication:
https://softwareengineering.stackexchange.com/questions/367768/how-to-avoid-dto-on-a-client-server-application?noredirect=1#comment804724_367768
Related
When we develop using MVC pattern it happens to need to having additional methods that could achieve basic operations on our models.
An example is an agregate getter that return the total count of the user records on the persistence base.
int getUsersCount();
Where is the best place to put such of those methods? In the model? In the controller?
Is there any difference between specific SDK/languages?
Java EE
Android
Laravel
vanilla PHP
...
Thanks.
I found this article that discuss about it: here it is a overview comparison between Purist OOP and Anemic Domain Model .
The overview basically explains that there are two big difference in the way you can implement a MVC design pattern.
The first way is about concetrate the methods, like the aggregate getter in this case, in a model related controller class.
For example, in Android, when we persist models in local or remote database, or we have to serialize it, or to marshall it, we tend to create those kind of ModelController classes and have so an anemic MVC pattern with clean POJO models.
class User extends MySuperModel{
int id;
String username;
//getters and setters
}
class UserController{
User getUserById(int id);
int getUsersCount();
}
The other way, consists in concentrate all the methods in the model class itself, for example as in Laravel (where controllers are demand to mainly control the post-routing and pre-rendering of a view, but doesn't tends to have other methods and neither their easy to instantiate. In this case we have a controlled domain MVC, and the additional model related methods should be in the model class itself.
class User extends Eloquent\Model{
protected $fillable = ['id', 'username']
function getUserById($id);
function getUsersCount();
}
We have a front-end service that uses a back-end service to get a list of Metric objects. We've written a Java ClientSDK for the back-end service to make life easier for development of client applications of that service.
We also expose a list of Metrics from the front-end service. For now, we're directly exposing and converting the back-end Metric objects to JSON.
My concern is that if changes are made to the back-end Metric object - say a developer adds a new secret ID field - we don't want to expose it from the front-end service.
We're also writing a clientSDK for the front-end service. We don't want to reference the Metric class from the back-end clientSDK, so the logical option is to define a similar Metric object in the front-end SDK.
I don't want to waste CPU cycles copying 1000's of Metrics from one class definition to another.
Is there a way to specify which fields I should expose from the back-end Metric to the front-end definition of Metric as I'm converting to JSON? Better yet, can I reference the front-end definition to the JSON converter as I ask it to marshal the back-end object?
We're using Jackson with the Spring rest framework for context, but I'd be happy to drop that in a heartbeat since marshaling objects via annotations seems to be the root cause of this problem.
Take a look at Jackson's JsonView construct.
I can see your example looking something like this:
class Views {
static class Client {}
static class Backend extends Client {}
}
public class Metric {
#JsonView(Views.Client.class) String metricName;
#JsonView(Views.Client.class) String count;
#JsonView(Views.Backend.class) String secretKey;
}
The #JsonView annotation is supported on Spring #ResponseBody annotated methods as of Spring 4.1.
As Nicholas Hausschild has suggested you can achieve this by annotations with your marshalling/unmarshalling framework.
However you can simply use inheritance and casting like this:
class SomeSuperClass {
String exposeThis;
String exposeThat;
// getters and setters...
}
class SomeSubClass extends SomeSuperClass {
String doNotExposeThis;
// getters and setters...
}
This way you can cast to the super class when returning an object to the JSON parser, and at the same time use the subclass internally to carry additional information which you don't really want to expose.
Another possibility is the use of Mixins, so you can define different scenarios without touching the original DTO.
I myself use a library I wrote to achieve this dynamically:
https://github.com/Antibrumm/jackson-antpathfilter
This works well for not too deep graphs, else someone wrote another approach in a similar way here which seems more performant for these scenarios, but behaves a bit different.
https://github.com/krishna81m/jackson-nested-prop-filter
In a project I am currently working on, HAL support through the REST API is obtained by extending Springs org.springframework.hateoas.ResourceSupport, in order that links can be added to an object.
A quick example:
public class MyDataRepresentation extends ResourceSupport {
private String name;
}
Now in the web layer, I can add links in to the representation:
MyDataRepresentation myData = someService.getTheData();
myData.add(new Link(someUrl, someRel));
All well and good.
The problem is that I would rather re-use the domain object (MyData) directly, and not create a separate class in the web representation layer in order to accomplish this. The reason for this, is that my application in this particular case is simple enough that the domain object can be used directly, and I wish to avoid having mapping logic to translate to/from the web layer, either hand-coded or using a mapping tool. A further argument against mapping logic is that business logic often creeps into mapping logic, making the business logic even harder to follow.
So here is the domain class:
public class MyData {
private String name;
}
Unfortunately this does not give me anywhere to attach my HAL links to.
So my question is, is there a HAL framework for Java, that lets me directly re-use domain objects in the web layer without resorting to using 'extends' and forcing my down the route of web/domain mapping logic?
Some other way of using HAL support in Spring that lets me do this? What about HAL support in Jersey, is that less obtrusive?
In my java program, I had a book class and a library class.
The library stores the book object in an array list and then I display it on the screen.
I can add the book and remove the books using functions.
I also use AbstractJtableModel for adding and removing the books.
But now I want to use a database, MySQL, instead of an array list.
How should I change my program?
well, you need to write the whole application :)
you need to create a db, with at least one table, you need to add mysql jdbc library to classpath and using jdbc you can insert/select/update/delete data from DB.
Alternatively, you need to add jdbc and use ORM framework like Hibernate, but depending on your Java knowledge this way can be harder (but easier to maintain in future, if you create big application). Here you can download simple hibernate application, which does CRUD operations with Honey :), you can extract interface similar to suggested by Javid Jamae from TestExample class, and exchange Honey class with Book according to your needs
You might consider using the Data Access Object (DAO) pattern. Just do a Google search and you'll find tons of articles on the topic. Essentially, you'll create a LibraryDao interface with methods like:
public interface LibraryDao {
public void storeLibrary(Library library)
public Library loadLibrary(long id)
public List<Library> searchByTitle(String title)
//...
}
You can implement this interface with straight SQL, or you can use an Object Relational Mapping (ORM) tool to implement it. I highly recommend reading up on Hibernate and the JPA specification.
Abstract the retrieval and storage of the books into a class by itself - you don't want that persistence logic intermingled with your business logic. I'd suggest creating an interface called something like "BookStorageDAO" and then you can have various implementations of that interface. One implementation may be to store the books in an ArrayList while another may be to store the books in a Database.
In this way, you can utilize the interface in your business logic and swap out the implementation at any time.
You would still use the ArrayList in your GUI to persist and display the data. The difference would be you need logic to save and load that ArrayList from a database so that the data is stored even after the program ends.
Side note, extends DefaultTableModel as opposed to AbstractJtabelModel. It completes some of the methods for you.
You don't need a DAO per se, but those answers aren't wrong.
Separation of Concern
What you need to do is separate your application based on concern, which is a pattern called separation of concern. It's a leak to have concerns overlap, so to combat this, you would separate your application into layers, or a stack, based on concern. A typical stack might be include:
Data Access Layer (read/write data)
Service Layer (isolated business logic)
Controller (Link between view and model)
Presentation (UI)
etc., but this will only partly solve your problem.
Program To The Interface
You also (as the others have mentioned) need to abstract your code, which will allow you to make use of dependency injection. This is extremely easy to implement. All you have to do is program to the interface:
public interface PersonService {
public List<Person> getAllPersons();
public Person getById(String uuid);
}
So your application would look like this:
public class PersonApp {
private final PersonService personService;
public PersonApp(PersonService personService) {
this.personService = personService;
}
}
Why is this better?
You have defined the contract for interacting with the Person model in the interface, and your application adheres to this contract without having any exposure to the implementation details. This means that you can implement the PersonService using Hibernate, then later decide you want to use JPA, or maybe you use straight JDBC, or Spring, etc. etc., and even though you have to refactor the implementation code, your application code stays the same. All you have to do is put the new implementation on the classpath and locate it (tip: the Service Locator pattern would work well for that).
I have a requirement in my application. My tables won't be defined beforehand.
For example, if a user creates a form by name Student, and adds its attributes like name, roll no, subject, class etc, then on runtime, there should be a table created by name student with columns name, roll no, subject, class etc. And also its related class and its Hibernate mapping file.
Is there any way of doing so?
Thanks in advance,
Rima Desai
Hibernate supports dynamic models, that is, entities that are defined at run-time, but you have to write out a mapping file. You should note a couple things about dynamic models:
You may be restricted in how you define these at run-time (viz. you will have to use the Session directly instead of using a helper method from HibernateTemplate or something like that).
Dynamic models are supported using Maps as the container for the fields of an entity, so you will lose typing and a POJO-style API at run-time (without doing something beyond the baked-in dynamic model support).
All of that said, you didn't mention whether it was a requirement that the dynamically defined tables be persistent across application sessions. That could complicate things, potentially.
It's possible, but it's not clear why would you want to do something like that, so it's hard to suggest any specific solution.
But generally, yes, you can generate database tables, hibernate classes and mappings dynamically based on some input. The easiest approach is to use some template engine. I've used Velocity in the past and it was very good for this task, but there are others too if you want to try them.
EDIT:
Following OP clarification the better approach is to use XML to store user defined data.
The above solution is good but it requires recompiling the application whether forms are changed. If you don't want to stop and recompile after each user edit, XML is much better answer.
To give you some head start:
#Entity
public class UserDefinedFormData {
#Id
private long id;
#ManyToOne
private FormMetadata formMetadata;
#Lob
private String xmlUserData;
}
Given a definition of the form it would trivial to save and load data saved as XML.
Add a comment if you would like some more clarifications.
last week I was looking for same solution and then I got idea from com.sun.tools.javac.Main.compile class, you create the Entity class using java IO and compile using java tools, for this you need tools.jar to locate on CLASS_PATH, now I am looking for run time hibernate mapping without restart.
some one was saying in the post regarding to this type of requirement that "but it's not clear why would you want to do something like that" answer is this requirement is for CMS(Content Management System). and I am doing the same. code is as below.
public static void createClass()
{
String methodName=“execute”;
String parameterName=“strParam”;
try{
//Creates DynamicTestClass.java file
FileWriter fileWriter=new FileWriter(fileName,false);
fileWriter.write(“public class “+ className +” {\n”);
fileWriter.write(“public String “+methodName +“(String “+parameterName+“) {\n”);
fileWriter.write(“System.out.println(\” Testing\”);\n”);
fileWriter.write(“return “+parameterName +“+ \” is dumb\”;\n }\n}”);
fileWriter.flush();
fileWriter.close();
String[] source = { new String(fileName) };
com.sun.tools.javac.Main.compile(source);
}