I created a simple Web Server which use Hibernate to store entities on a MySQL database. Also, as you can expect, it shares some libraries with the clients in the <...>.shared> package to access various resources. Among them, there are the POJO classes, annotated with both Hibernate and Jackson annotations. This is an example of a POJO class.
#JsonInclude(Include.NON_NULL)
#Entity
#Table(name = "user", uniqueConstraints =
{ #UniqueConstraint(columnNames = "email"),
#UniqueConstraint(columnNames = "nick") })
public class User implements java.io.Serializable, RecognizedServerEntities
{
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer userId;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "threadAuthor",
orphanRemoval = false)
#Cascade({ CascadeType.SAVE_UPDATE })
private Set<Thread> userThreads = new HashSet<Thread>(0);
}
Now, I'm trying to create an android app that simply use these shared classes: the app doesn't need to know anything about Hibernate, Javax.persistence and maybe even Jackson annotations.
However, when I create a new Android project, it requires a lot of libraries.
74K hibernate-commons-annotations-4.0.5.Final.jar
5,1M hibernate-core-4.3.6.Final.jar
38K jackson-annotations-2.4.0.jar
221K jackson-core-2.4.3.jar
1,1M jackson-databind-2.4.3.jar
180K javax.persistence_2.1.0.v201304241213.jar
714K org.restlet.jar
55K shared.jar
Problem is that they greatly magnify the app size and slow down the development process, because I have to enable Multidex support.
So, how can I solve?
I can think of some solutions:
Change the shared classes in some way to not expose the annotations. Is it a viable solution? How can I efficiently do this?
Use ProGuard. I don't know if it's really a solution because I don't know anything about this tool, but for what I've read it could help to delete classes that aren't used at all in the project.
EDIT: I partially worked around the problem extracting only required casses from hibernate-core-4.3.6.Final.jar, which is the greatest libraries. Still looking for most elegant solutions.
If you think of your application as having layers, you are currently using the same classes across the data access and view layers.
Your database isn't interested in the Jackson annotations, and your Android client isn't interested in the Hibernate annotations.
Two different approaches that I have seen for this are:
- have a parallel 'view' layer representation of your objects that has the Jackson annotations which your application will populate by mapping from your Hibernate annotated data access layer
OR
- have your client application not share the classes of the server application. It parses the JSON and maps the structures into your own client specific model.
These approaches are equivalent, but just vary by where the mapping takes place.
Related
I'm building an android project, I have a database and I create many entity classes (which has all sorts of annotations like #id, #Nullable). Now I need to show the data in my view.
I'm wondering if it's ok to use directly entity classes in the view (e.g. adapter), or it's better to convert them first in VO object? How to organise things in a clearer way ? Do I need to create a converter for each entity ?
Thanks.
Maybe the MVVM pattern is what you are looking for. Your entity classes (Models) are "wrapped" by ViewModels. The ViewModels expose the data to your UI and accept user input.
There's no need for a 1:1 mapping between Models and ViewModels. Your ViewModel (e.g. for a whole screen) can hold several different Models and interact with them.
I'm a bit confused, as from a long time i am saving the json response directly to an ArrayList> and displaying to my listView, but now, looking on other people code i noticed that they are using POJO class to interact with JSON, Is it is better way? if it is please explain why? cause using POJO means I have to write extra code, But if saving the response directly to the arraylist make my work done, then why should i use a POJO class?
So, Pojo usage better due to OOP pattern, because you work at runtime with your Java object without intermediate Json parse. Manual json parsing too ugly due to code style(its my opinion).
But if saving the response directly to the arraylist make my work done
If, you collect your object in Maps, you can apply different features out of the box(sort, compare etc) to your map, but in case when your map contains POJO instead of JSONS.
Encapsulation. When you work with dates for examples or with type, its pretty good to use getters/setters for data mapping instead of manual parsing again and again.
4.Object scaling and mapping:
Lets image that we have some object user:
public class User{
int id;
#SerializedName("specific_id_for_blah_blah")
private int mSpecId
#SerializedName("date_of_birthaday")
private String mBDay;
public Date getBirthday() {
return new Date(mBDay);
}
}
What I want to say by this example.
You can map your json to POJO with one line of code only
User user = new Gson.fromJson(response, User.class);
Pretty simple isn't?.
Name serialization. When your response contain key name which looks to long or weird, you can use your own style naming with easy changes, just with small annotation. mSpecId returns value of "specific_id_for_blah_blah"
Platform specific encapsulation. You can use only platform specific object at your runtime, instead parsing operations in your business logic. String with data -> Date or Calendar
Also you can override Object methods in your POJO (equals, hashcode, toString) for your logic spec. operations.
If your serverside change some key you can change name of key in POJO instead looking through where you parse it before. IN same case you can add new field and setter/getter, if some of parameter will be added to your response
There is no right and wrong answer here. It all depends on your use case. If your solution works, and you are happy with it, I don't see why do you need to change it.
If I had to choose, I would go with a POJO class to represent the response, but this is a subjective opinion. I think that you have the following benefits:
It's cleaner - having a separate, dedicated class to represent your payload gives you the ability to be more specific in your code. You are no longer manipulating Maps of key - value pairs, but instances of a specific class, that can have a more specific behaviour. You can specify natural ordering, criteria for equality, etc - things that may be useful for your program's logic
It's simpler - I would prefer calling a getter every time then accessing a map by a property name and getting an Object back. The logic of the program will be much simpler and safer.
It's better in terms of OOP best practices - the whole point behind OOP is to have objects, that define properties and behaviours. IMHO, using POJOs to represent responses forces you to adhere more closely to best practices.
There are also some cases that will fit the no - POJO approach better - for example, if you only display your data, not manipulating it in any way inside the app. Or if you want to shave off some time for the complex parsing that may be needed if you are trying to inflate object hierarchies.
My best suggestion is - profile your app, check your use cases and make an educated decision which approach is better.
We are building a project using couchbase. On Android, I use couchbase lite. Usually, I've been working with relational databases and because I am new to couchbase I am having trouble finding the "correct" architecture. I do understand the core concepts I think, but all the samples and guides seem to stick to some kind of easy setup where they access the database right in the Activities.
I am more used to having some database abstraction where the business logic only get's to see POJO DTO's that are delivered through a database interface or some DAO or something. So I've now annotated my model classes and started writing a simple OR mapper, but with different types of data, foreign keys etc. this is getting quite time consuming quite fast.
Am I completely missing the point here somehow? I can't imagine everyone doing it this way? I everyone writing methods that convert Documents to POJO model classes for each class seperately? Or using a json parser to do that (But that won't work for foreign keys if I wan't to load them too, does it)?
Sorry for the load of questions, but I feel I am missing something obvious here. Thanks!
Will try answering your questions:
Am I completely missing the point here somehow?
No. You can treat noSQL CB as a persistent distributed object cache. So its not RDBMS. However, DAO pattern perfectly fits into this model...since you are dealing with DTOs/ValueObjects/POJOs on DAO level and on noSQL level.
I can't imagine everyone doing it this way?
I suggest write one universal Couchbase manager class that can persist/retrieve a POJO. Then you can re-use it in your DAOs.
Everyone writing methods that convert Documents to POJO model classes
for each class separately? Or using a json parser to do that (But that
won't work for foreign keys if I wan't to load them too, does it)?
You can have one common code in your Couchbase manager class that does conversion from/to json to POJO. So you work with only POJOs and don't see any json in your application code (outside of Couchbase manager class)
Here is an example of such class:
public class CouchbaseManager<K, V>
{
private final Class<V> valueTypeParameterClass;
#Inject
private CouchbaseClient cbClient;
#Inject
private Gson gson;
public CouchbaseManager(final Class<V> valueClass)
{
this.valueTypeParameterClass = valueClass;
}
public V get(K key)
{
V res = null;
String jsonValue = null;
if (key != null)
{
jsonValue = (String) cbClient.get(key);
if (jsonValue != null)
{
res = gson.fromJson(jsonValue, valueTypeParameterClass);
}
}
return res;
}
public void put(K key, V value)
{
int ttl = 0;
cbClient.set(key, ttl, gson.toJson(value, valueTypeParameterClass));
}
}
Then in your DAO code you create instance of CouchbaseManager for each type:
CouchbaseManager<String,Customer> cbmCustomer = new CouchbaseManager<String,Customer>(Customer.class);
CouchbaseManager<String,Account> cbmAccount = new CouchbaseManager<String,Account>(Account.class);
// and so on for other POJOs you have.
// then get/put operations look simple
Customer cust = cbmCustomer.get("cust-1234");
cust.setName("New Name"); // mutate value
// store changes
cbmCustomer.put(cust.getId(), cust);
Now regarding "foreign keys". Remember its not RDBMS so its up to your code to have notion of a "foreign key". For example a Customer class can have an id of an account:
Customer cust = cbmCustomer.get("cust-1234");
String accId = cust.getAccountId();
//You can load account
Account acc = cbmAccount.get(accId);
So as you can see you are doing it all yourself. I wish it was JPA or JDO implementation/provider for Couchbase (like DataNucleus or Hibernate)
You should really start with your POJO/Document design to try to split your POJO entities into "chunks" of data to get a right balance between coarse vs fine grained POJOs.
Also see this discussion on key/document design considerations.
I'm currently into evaluating GreenDAO for my application. I'm facing the following problem.
My app consists of several modules (seperated in packages, e.g. "com.example.app.results", "com.example.app.synchronization"). Some of them have no dependencies, some of them have dependencies on other modules (e.g. synchronization has a dependency on results, whereas results has no dependency).
What I would like to model is the following:
Module results has Entity MyResult (attributes: name, value).
Module synchronization has Entity MyResultSynchronization (attributes: MyResult (reference), date).
final Schema schema = new Schema(1, "com.example.app");
final Entity myresult = schema.addEntity("results.MyResult");
final Property myresultId = myresult.addIdProperty().getProperty();
myresult.addStringProperty("name");
myresult.addStringProperty("value");
final Entity myResultSynchronization = schema.addEntity("synchronization.MyResultSynchronization");
myResultSynchronization.addIdProperty();
myResultSynchronization.addDateProperty("date");
myResultSynchronization.addToOne(myresult, myresultId);
but - $entityPackage.$name does not what I expected it to do (neither did $package\$name ;-)).
My question is: Am I forced to have all entities of my app in a single package? Is what I'm trying to do feasible by creating multiple Schemas - but than again, is it possible to use the relate-feature between two (or more) schemas? What is the "right" way to do it? (Is there one?)
Indeed all entities have to be in the same package.
Normally you use a structure like
com.example.myapp.data
Where you put everything for managing your database, especially your entity classes. Inside you can let greendao create a dao package where it will put everything needed to access your data (base).
Of course you can enforce your naning schema by making multiple sxhemas in greendao. But the schemas will be independent: They won't use the same database and you won't be able to link them together with toOne () for example.
If you still want to use your naming schema you can generate everything to an intermediate package and move them to your desired packages manually. But you would have to repeat this upon every change to your database schema, which is more often than one may think at first.
I've been trying to create a database where all the tables inherit a certain element in order to have to possibility to have meta-data.
there for I added in the model generator in all the table declarations this line:
public Entity addSuperEntity(Schema schema) {
Entity superEntity = schema.addEntity("superEntity");
superEntity.addIdProperty().primaryKey();
// SET RELATIONSHIP 1:m TO META DATA
}
public Entity addTable(Schema schema) {
Entity mEntity = schema.addEntity("MyEntity");
mEntity.setSuper("superEntity");
mEntity.addIdProperty().PrimaryKey();
// REST OF FIELDS
}
the question is:
now after I generated this to my Android project, how can I make sure that this still happens in real life? do I need to change anything now?
the official documentation doesn't have anything about inheritance.
Inheritance is supported for non-entity super classes using setSuperclass(String). An alternative is implementing interfaces using implementsInterface(String).
I updated the official docs with some details in the new section on inheritance and interfaces:
http://greendao-orm.com/documentation/modelling-entities/