I have 2 similar schemas in simple database - "develop" and "stage". I have generated Java classes with Jooq for one of that schemas ("develop" for example). When jooq generates query to db, it implicitly add schema's name to all query's aliases
select "develop"."image"."id", "develop"."image"."image_data"
from "develop"."image"
where "develop"."image"."id" = ?
So my question is, whether there are the way to change jooq schema name (for "stage" as an example) in generated query without regenerating jooq's classes for "stage" schema?
You have several options, which can even be combined:
Use the code generator's schema mapping feature
If you want to avoid hard-wiring the "develop" schema name into your generated classes, you can rewrite that to some other schema name like this:
<configuration>
<generator>
<database>
<schemata>
<schema>
<inputSchema>develop</inputSchema>
<outputSchema>stage</outputSchema>
</schema>
...
Of course, this just postpones the problem, because the schema name is still in the generated code. You can remove the name entirely from generated code by using the following option:
<configuration>
<generator>
<database>
<schemata>
<schema>
<inputSchema>develop</inputSchema>
<outputSchemaToDefault>true</outputSchemaToDefault>
</schema>
...
This will now remove any schema references from generated code, so the generated classes can run on all your schemas (be sure to use the correct connection and search_path, of course!)
I think this is the best option for you
More details here:
https://www.jooq.org/doc/latest/manual/code-generation/codegen-advanced/codegen-config-catalog-and-schema-mapping/
Use the runtime schema mapping feature
You can leave generated code as it is and rewrite all object references at runtime using Settings (which you supply to your jOOQ runtime Configuration). Again, you have the same two options:
Mapping the schema name:
new Settings().withRenderMapping(new RenderMapping()
.withSchemata(new MappedSchema()
.withInput("develop")
.withOutput("stage")
)
);
Removing all schema names:
new Settings().withRenderSchema(false);
More details here:
https://www.jooq.org/doc/latest/manual/sql-building/dsl-context/custom-settings/settings-render-mapping/
Related
When i'm generating java classes from jooq generator, i get one field deprecated :
/**
* #deprecated Unknown data type. Please define an explicit {#link org.jooq.Binding} to specify how this type should be handled. Deprecation can be turned off using <deprecationOnUnknownTypes/> in your code generator configuration.
*/
#java.lang.Deprecated
public final TableField<PositionRecord, Object> COORDINATES = createField("coordinates", org.jooq.impl.DefaultDataType.getDefaultDataType("point"), this, "");
I am not sure to know how to define the binding on my maven configuration with the "Point" type.
Any ideas ?
Edit :
<configuration>
<!-- JDBC connection parameters -->
<jdbc>
<driver>com.mysql.jdbc.Driver</driver>
<url>jdbc:mysql://localhost:3306/${jooq.generation.schema}</url>
<user>${jooq.generation.user}</user>
<password>${jooq.generation.password}</password>
</jdbc>
<!-- Generator parameters -->
<generator>
<generate>
<javaTimeTypes>true</javaTimeTypes>
</generate>
<database>
<name>org.jooq.util.mysql.MySQLDatabase</name>
<includes>.*</includes>
<dateAsTimestamp>true</dateAsTimestamp>
<!-- In case your database supports catalogs, e.g. SQL Server:
<inputCatalog>public</inputCatalog>
-->
<inputSchema>${jooq.generation.schema}</inputSchema>
</database>
<target>
<packageName>${jooq.generation.package}</packageName>
<directory>target/generated-sources/jooq</directory>
</target>
</generator>
</configuration>
So far i've been able to use my java classes generated by this configuration. But some fields are deprecated because of some "Data type" not recognized. So i've found out that we could kinda use "force type" and put it in the maven configuration + adding the corresponding binding to let know jooq about this data type. For instance in our case : we want to be able to reach the field "Coordinates" ( as a Point type in java). I hope i was clear enough.
You've already answered your question:
So i've found out that we could kinda use "force type" and put it in the maven configuration + adding the corresponding binding to let know jooq about this data type
That's the correct way, you need to use a data type binding: https://www.jooq.org/doc/latest/manual/code-generation/custom-data-type-bindings
Follow the instructions from the manual and you'll be fine.
I am generating a set of JOOQ records from a schema using JOOQ 3.6.4 with Java 8.
Some of the tables are reference data that are similarly structured, let's say they have ID, CODE and VALUE columns (they might have other columns, but they all have at least these columns).
In my code, not generated by JOOQ, I have an interface "ReferenceData" that defines accessors that match the code that JOOQ generates for these three columns. I want to tell JOOQ to add an "implements ReferenceData" clause to the Record objects it generates (the code that JOOQ already generates will automatically implement the interfaces).
I'm not asking that JOOQ automatically figure out the interfaces, I'm fine with listing what interfaces each table should implement in the XML configuration.
Question 1: is there any way to configure JOOQ to generate an implements clause without writing a custom generator class?
If I have to write a custom generator class - I still want the definition of what table records implements what interfaces to be in the XML config.
Question 2: Is there an example somewhere of defining custom data in the XML that is communicated down into the custom generator class?
This can be done using
Generator strategies
Matcher strategies (which are built-in, XML-based generator strategies)
Generator strategy
With a generator strategy, you'll implement the following code:
public class MyStrategy extends DefaultGeneratorStrategy {
#Override
public List<String> getJavaClassImplements(Definition definition, Mode mode) {
if (mode == Mode.RECORD && definition.getQualifiedName().matches("some regex")) {
return Arrays.asList(MyCustomInterface.class.getName());
}
}
}
The above can then be hooked into your code generator configuration as such:
<generator>
<strategy>
<name>com.example.MyStrategy</name>
</strategy>
</generator>
Matcher strategy
With a matcher strategy, you'll essentially write:
<generator>
<strategy>
<matchers>
<tables>
<table>
<expression>A_REGEX_MATCHING_ALL_RELEVANT_TABLES</expression>
<recordImplements>com.example.MyCustomInterface</recordImplements>
</table>
</tables>
</matchers>
</strategy>
</generator>
As you can see, matcher strategies are easier to configure than generator strategy, for simple use-cases like yours.
I'm using the Java Persistence API to describe tables from my database that i will manipulate in my code.
However, the schema used is not be the same depending on where my project will be installed. So, when I use the annotations, I would like that the SCHEMA field was a variable, but I can't make it:
#Entity
#Table(name = "TABLE_NAME", schema = schemaVariable, catalog = "")
How can I achieve that?
Is it possible with the persistence.xml file?
No, this is not possible. You can only use compile-time constants (which are all primitives and String) in annotations.
You can use final variables:
public class DatabaseMetadata {
public static final SCHEMA = "MySchema";
}
and then use it in annotation:
#Table(name = "TABLE_NAME", schema = DatabaseMetadata.SCHEMA, catalog = "")
but I think it's not what you wanted.
PS. On the other hand, there can be find examples of using i.e. Spring EL in annotations (see #Value annotation), but this requires custom annotation processor. AFAIK none of JPA providers gives you such ablility.
Putting schema information (like table, column, schema names) in java classes is a bad idea any time IMHO (forcing recompile if you want to deploy elsewhere). You could put that info in orm.xml and just deploy a different orm.xml dependent on your deployment requirement.
As for persistence.xml you would be dependent on your JPA provider having a persistence property that defined the default schema/catalog. I know DataNucleus JPA (what I use) has this, but no idea for Hibernate
If you know that you would be using different schemas, I'd suggest to use 2 mapping files and define
<entity-mappings>
<persistence-unit-metadata>
<persistence-unit-defaults>
<schema>HR</schema>
</persistence-unit-defaults>
</persistence-unit-metadata>
...
</entity-mappings>
In this way you will be able to easily change schemas, without any changes in the application code.
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.