I am using hibernate reverse engineering and trying to get my Timestamps to map to a JodaTime type.
I have setup my hibernate.reveng.xml file properly
<sql-type jdbc-type="TIMESTAMP" hibernate-type="org.joda.time.contrib.hibernate.PersistentDateTime" not-null="true"></sql-type>
The issue is that when i run the rev-eng process my Java classes also get the members created as PersistentDateTime objects, but I don't want that because they are not usable. I need the java objects to be org.joda.time.DateTime
So I tried creating a custom engineering strategy
public class C3CustomRevEngStrategy extends DelegatingReverseEngineeringStrategy {
public C3CustomRevEngStrategy(ReverseEngineeringStrategy res) {
super(res);
}
public String columnToHibernateTypeName(TableIdentifier table, String columnName, int sqlType, int length, int precision, int scale, boolean nullable, boolean generatedIdentifier) {
if(sqlType==Types.TIMESTAMP) {
return "org.joda.time.DateTime";
} else {
return super.columnToHibernateTypeName(table, columnName, sqlType, length, precision, scale, nullable, generatedIdentifier);
}
}
}
My thought was that the hibernate mapping files would get the hibernate.reveng.xml file settings and the java objects would get the settings from the custom strategy file...but that was not the case. Both the mapping file and Object are of type "org.joda.time.DateTime" which is not what I want.
How can I achieve my goal? Also, I am NOT using annotations.
Hibernate 3.6
JodaTime 2.3
JodaTime-Hibernate 1.3
Thanks
EDIT: To clarify exactly what the issue is
After reverse engineering this is what I get in my mapping file and POJO class
<property name="timestamp" type="org.joda.time.contrib.hibernate.PersistentDateTime">
private PersistentDateTime timestamp;
As a POJO property, PersistentDateTime is useless to me as I cannot do anything with it such as time manipulations or anything. So this is what I want after my reverse engineering
<property name="timestamp" type="org.joda.time.contrib.hibernate.PersistentDateTime">
private org.joda.time.DateTime timestamp;
Using the Jidira library as suggested below gives me the same result, a POJO that I cannot use.
The JodaTime-Hibernate library is deprecated, and is probably the source of your problem. Don't dispair however as there is a (better) alternative.
You will need to use the JadiraTypes library to create the correct JodaTime objects from Hibernate. Add the library which can be found here to your project classpath and then change your type to org.jadira.usertype.dateandtime.joda.PersistantDateTime. All of the JodaTime objects have a corresponding mapping in that package, so if you decide to change to another object then just update your type.
This should ensure that your objects get created correctly.
I should add a caveat to my answer, which is that I have never used the JadiraTypes library with Hibernate 3. If it only supports Hibernate 4 (I don't see why it would, but...) let me know and I'll delete my answer.
The Hibernate Tools don't seem to separate Hibernate Types from the Java types. If you would be using annotations, this would be more clear as in that case you'd need an #Type annotation, which Hibernate will not generate at all. So using the exposed APIs won't help here.
Fortunately, Hibernate lets you plug into the actual code (or XML) generation after it does its processing. You can do that by replacing the Freemarker templates it uses to generate both XML and Java code. You'll need to use Ant for reverse engineering, however.
To start using Ant for this purpose (if you're not doing so already), you can either pull Hibernate Tools in as a build-time dependency using your dependency manager or download a JAR. Put the jar in Ant's classpath, but also extract the template files from it: since you're using XML configuration, you'll be interested in the /hbm directory. Then add the task using <taskdef> and, assuming that you extracted the templates to TPL_PATH/hbm/*.ftl, call it using <hibernatetool templatepath="TPL_PATH" ...>. (For more info, see below for a link to the docs). Using Ant also helps with automation, for example on CI servers where you won't have Eclipse.
You'll want to keep hibernate-type="org.joda.time.DateTime" in your hibernate.reveng.xml so that the Java files get generated correctly, but replace it with org.joda.time.contrib.hibernate.PersistentDateTime in the generated XML. To do that, edit TPL_PATH/hbm/property.hbm.ftl, replace ${property.value.typeName} with ${javaType}, and assign javaType to the right value before it's used:
<#assign javaType=property.value.typeName>
<#if javaType.equals("DateTime")>
<#assign javaType="org.jadira.usertype.dateandtime.joda.PersistentDateTime">
</#if>
<property
name="${property.name}"
type="${javaType}"
...
You might want to remove newlines to keep the generated XML clean.
This is all described in the Hibernate Tools documentation at http://docs.jboss.org/tools/archive/3.2.1.GA/en/hibernatetools/html/codegen.html#d0e6349 - except that the documentation doesn't tell you exactly which templates you need to modify, you need to figure that out by reading the templates.
Related
I am doing some debugging on code that throws errors on certain fields during a database query, and some constructor actions of a load method.
We are setting properties manually on an object before creating an instance of a class/model, however for some reason these fields (DateCreated, DateUpdated) are returning null shortly after passing them.
We have validated that these fields are in fact NOT null up until this point, so our concern is that the GORM is deleting and attempting to replace these fields because of naming convention, and perhaps we should leave our own manual setting of these fields out, and allow GORM to manage them.
Is there are way to see which version of GORM the grails app is using, and perhaps get some understanding of how this is managing these fields, and using its own generated constructor for this object?
Depends which version for grails you are using. Assuming you are on newer grails version. The GORM version should be specified in gradle.properties file inside of your grails project and it looks like this:
grailsVersion=3.3.2
gormVersion=6.1.8.RELEASE
gradleWrapperVersion=3.5
You can also find it out from gradle dependency tree with this gradle task:
./gradlew dependencies
We are setting properties manually on an object before creating an
instance of a class/model...
It isn't possible to set properties on an object before creating it.
...so our concern is that the GORM is deleting and attempting to
replace these fields because of naming convention
You haven't said what the property names are but if they are dateCreated and lastUpdated, then GORM will treat those properties specially. If you don't want that, you can turn auto time stamping off, as shown below...
class Person {
Date dateCreated
Date lastUpdated
static mapping = {
autoTimestamp false
}
}
See section 8.1.9 at http://gorm.grails.org/6.1.8/hibernate/manual/index.html#eventsAutoTimestamping.
I'm a java developer. I'm using spring 4.0.1 and hibernate 4.2.21. I have a class as follow:
#Entity
#Inheritance(...)
public abstract class Feature{
#Id
#GeneratedValue
protected Long id;
...
}
Now I have some many class as follow:
Label.java class:
#Entity
public class Label extends Feature{
protected String str;
...
}
Point.java class:
#Entity
public class Point extends Feature{
protected Integer intg;
...
}
I have more than 20 Entity class that extends from Feature class. Is there any way to add dynamically this classes(such as Label and Point) to the project without writing hard code?
update:
For example, Hibernate get data from a database and then according this data, create models.
Is it possible?
How do I do?
I think its not a good database design that needs to be changed dynamically. It sounds verbose and not consistent. Observe your domain again and try to design a proper entity relationships that wouldnt be changed over run time.
You can try to collect the needed data to build the model and generate a hibernate hbm.xml file for each entity (is xml format and easy to generate with java after reading the data needed as you describe in your update)
After that, you can create programmatically a hibernate configuration object following this http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/session-configuration.html#configuration-programmatic
I Think with that approach you can achieve what you want if I understand well your question.
I think you want to generate your entity class at runtime instead of that you have to write your java file and compile it and so on.
If this is your requirement you can use a byte code generator like javassist to generate and annotate your class file at runtime. Then you can persist it to your table using JPA, Hibernate and any other ORM framework.
As I understand you need to develop a tool, collects table names that have one-to-one relationship with Feature table.
My suggestion is like that (tested with Oracle):
1) From your DB, get tables metadata who is referancing your Feature table.
Below will print your Label, Point, etc tables who has foreign key relation to your table.If you want to only generate a subset (irrelevant tables might has this relationship too) may be you put a common foreign key column name and filter out non-related tables with a help of such marking.
Connection connection = jdbcTemplate.getDataSource().getConnection();
DatabaseMetaData metaData = connection.getMetaData();
ResultSet exportedKeys = metaData.getExportedKeys(connection.getCatalog(), "<your_schema_name>", "FEATURE");
while (exportedKeys.next()){
String fkTableName = exportedKeys.getString("FKTABLE_NAME");
String fkColumnName = exportedKeys.getString("FKCOLUMN_NAME");
System.out.println("[fkTableName:" + fkTableName + "], [fkColumnName" + fkColumnName + "]");
}
exportedKeys.close();
2) For the tables you collected above, for each table of our concern, get table metadata for the types and columns.
ResultSet columns = metaData.getColumns(connection.getCatalog(), "<your_schema_name>", "<your_table_name>", null);
while (columns.next()){
String columnName = columns.getString("COLUMN_NAME");
String typeName = columns.getString("TYPE_NAME");
System.out.println("[columnName:" + columnName + "], [typeName" + typeName + "]");
}
columns.close();
3) According to result from 2 generate your Java classes. With fields, getter setters, annotations etc. Then copy them into your source directory. You know the rest :)
Hope this is helpful.
I think you can use Hibernate Reverse Engineering to generate Entity for all the database tables. Please refer this Link. That will explained step by step process to generate entity from database using hibernate reverse engineering.
Do not repeat yourself.
If you really need those classes use an IDE (like eclipse) to generate the classes. Or use generics and inheritance to create only one class that is capable of storing Strings as well as Integers.
But if you do not actually need classes, generate SQL (not JPQL nor HQL) and to store the data in java.util.Map and similar data structures.
Classes are good for:
type safety
combining logic (methods) with data (fields)
describing relationships
In your case you might only need:
store structured data at runtime.
I think you could do this with eclipse, but the classes had to be modified more or less to preserve the inheritance hierarchy.
Righ click on the project name and select Properties
Use project facets if project facets not enabled
Click the JPA if it's not selected, then click OK to close the project properties window.
After enabling JPA in project properties, now right click you eclipse project name again, you should see a new context menu item JPA tools appears. Choose Generate Entities from tables
Select a database connection to let Eclipse get the tables used to generated
class from.
Here is how to setup db in eclipse
It's better to create the entities in a dummy project using the above method and copy the Entity classes to the real project.
Eclipse's Class refactoring may be used to preserve the inheritance hierarchy that you want.
Hope this helps.
I have set up Hibernate Tools from within Eclipse to autogenerate classes based on an existing DB. For each of the tables I have documented them and each of their columns within SQL Server. Is there a way to use that documentation information to comment the generated classes and to populate the schema entity documentation? I see that there are meta tags that can be put in the hbm.xml mapping files, but since I have those autogenerated each time I'd need to either add them back in or continually merge in new changes, plus I'd ideally like to have the DB be the "truth" information and not store this sort of information in the mapping files. Does anyone know if this is possible and if so how to do it? Thanks...
Is there a way to use that documentation information to comment the generated classes and to populate the schema entity documentation?
To my knowledge, tables and columns comments are used in some of the the generated files, at least in the following templates from hibernate-tools.jar:
doc/tables/table.ftl
hbm/column.hbm.ftl
hbm/persistentclass.hbm.ftl
For example, in hbm/column.hbm.ftl:
<#if column.isFormula()>
<formula>${column.getFormula()}</formula>
<#else>
<column name="${column.quotedName}" ${c2h.columnAttributes(column)}<#if column.comment?exists && column.comment?trim?length!=0>>
<comment>${column.comment}</comment>
</column><#else>/>
</#if>
</#if>
But they aren't used in the templates for annotated POJOs, you'd have to modify the templates for this.
If you use Hibernate tool task to generate pojo classes out of HBM files and Database,It will add documentation in the generated java classes by default.You can see it in pojoTypeDeclaration ftl file.
/**
${pojo.getClassJavaDoc(pojo.getDeclarationName() + " generated by hbm2java", 0)}
*/
<#include "Ejb3TypeDeclaration.ftl"/>
${pojo.getClassModifiers()} ${pojo.getDeclarationType()} ${pojo.getDeclarationName()} ${pojo.getExtendsDeclaration()} ${pojo.getImplementsDeclaration()}
Where pojo.getClassJavaDoc will generate documentation if your hbm file has meta attribute declared such as CLASS_DESCRIPTION.
when i run my hibernate tools
it reads from the db and create java classes for each tables,
and a java class for composite primary keys.
that's great.
the problem is this line
#Table(name="tst_feature"
,catalog="tstdb"
)
while the table name is required, the "catalog" attribute is not required.
sometimes i want to use "tstdb", sometimes i want to use "tstdev"
i thought which db was chosen depends on the jdbc connection url
but when i change the jdbc url to point to "tstdev", it is still using "tstdb"
so,
i know what must be done,
just don't know how its is done
my options are
suppress the generation of the "catalog" attribute
currently i'm doing this manually (not very productive)
or i could write a program that parses the java file and remove the attribute manually
but i'm hoping i don't have to
OR
find a way to tell hibernate to ignore the "catalog" attribute and use the schema that is explicitly specified.
i don't know the exact setting i have to change to achive this, or even if the option is available.
You need to follow 3 steps -
1) In the hibernate.cfg.xml, add this property
hibernate.default_catalog = MyDatabaseName
(as specified in above post)
2) In the hibernate.reveng.xml, add all the table filters like this
table-filter match-name="MyTableName"
(just this, no catalog name here)
3) Regenerate hibernate code
You will not see any catalog name in any of the *.hbm.xml files.
I have used Eclipse Galileo and Hibernate-3.2.4.GA.
There is a customization to the generation, that will tell what tables to put in what catalog.
You can specify the catalogue manually (in reveng file, <table> element), or programmatically (in your custom ReverseEngineeringStrategy class if I remember well).
Also, I recently had to modify the generation templates.
See the reference documentation :
http://docs.jboss.org/tools/archive/3.0.1.GA/en/hibernatetools/html_single/index.html#hibernaterevengxmlfile
you can customize the catalogue of each of your tables manually
https://www.hibernate.org/hib_docs/tools/viewlets/custom_reverse_engineering.htm watch a movie that explains a lot ...
http://docs.jboss.org/tools/archive/3.0.1.GA/en/hibernatetools/html_single/index.html#d0e5363 for customizing the templates (I start with the directory that's closest to my needs, copy all of them in my own directory, then edit as will)
Sorry, this could get more precise, but I don't have access to my work computer right now.
The attribute catalog is a "connection" attribute and should be specified in the "connection" config file hibernate.cfg.xml and NOT in a "data" config file *.hbm.xml.
I generate hibernate code via ant task <hibernatetool> and I put this replace task after regeneration (replace schema-name with your database).
<replace dir='../src' token='catalog="schema-name"' value=''>
So, after generation, attribute catalog has been removed.
This is a workaround, but code generated works in my development a production environment with different schema-name.
I'm using JAX-WS api for wsdl generation.
Java-bean class is something like:
public class MyBean {
private String nullableField;
private String notNullableField;
// and here appropriate get/set/ters
}
When wsdl is generated then nullability of this fields is not specified.
Question: what (and where) necessary to specify that fields have corresponding nillable='' value in wsdl? I.e. how can I specify fields nullability in plain java code for wsdl?
At this time I'm generating wsdl and then correcting xml manually for fields nullability. That's not convenient. I want this nillable attribute'll be generated by java-ws automatically.
Any suggestions?
Thanks.
AFAIK, it is still not possible to generate nillable=false when using #WebParam i.e. when using a Java-first approach (as discussed in this thread). Actually, I'd recommend to use a WSDL-first approach if you want fine control.