Implement interface in POJO if contains field - java

I generate java classes with jOOQ. And I want to make POJOs implement an interface which contains only getters for fields. Obviously, I need this interface only in POJOs with such fields.
I need check class or table for field and, if field extists, implement interface in pojo.
Overriding getJavaClassImplements in DefaultGeneratorStrategy does not help because it adds the interface for all classes.

Configurative generator strategy
You seem to be implementing a programmatic generator strategy, just to let you know that there's also an option of a configurative strategy, which could look like this:
<configuration>
<generator>
<strategy>
<matchers>
<tables>
<table>
<expression>MY_TABLE</expression>
<pojoImplements>com.example.MyOptionalCustomInterface</pojoImplements>
</table>
</tables>
...
Please refer to the manual for more details. In order to apply this only to tables containing certain fields, just update the regular expression in <expression> to match those tables.
<expression>MY_TABLE1|MY_TABLE2</expression>
This expression has to be updated to be in sync with the schema, of course.
Programmatic genenerator strategy
Just like with the configurative strategy, you'll have to limit yourself to applying your logic only to generated POJOs. For this, notice the remark in the manual:
/**
* ...
* Beware that most methods also receive a "Mode" object, to tell you whether a
* TableDefinition is being rendered as a Table, Record, POJO, etc. Depending on
* that information, you can add a suffix only for TableRecords, not for Tables
* ...
*/
So, you'll have to do something like this:
#Override
public List<String> getJavaClassImplements(Definition definition, Mode mode) {
if (mode == Mode.POJO)
return Arrays.asList("com.example.MyOptionalCustomInterface");
else
return Collections.emptyList();
}
If you want to make sure that this inteface is only added to tables that match certain conditions, do this, instead:
#Override
public List<String> getJavaClassImplements(Definition definition, Mode mode) {
if (mode == Mode.POJO
&& definition instanceof TableDefinition t
&& t.getColumns().stream().anyMatch(c -> conditionHere(c)))
return Arrays.asList("com.example.MyOptionalCustomInterface");
else
return Collections.emptyList();
}

Related

How to check properties with Hibernate efficiently?

We are using Hibernate for Object/Relational Mapping. This works fine when loading entire entities. However, often I face the problem that I simply want to check a single attribute or COUNT() table entries based on a certain criteria. For sake of performance, I use Native SQL in those cases instead of loading several objects from database and checking their properties in Java. But having plain SQL queries is error-prone and I feel like it violates the idea of ORM.
So I wonder, is there any ORM approach to check single attributes with Hibernate efficiently?
Example: Let's assume we have two entity beans Order and OrderPosition. We want to check, if an order is partly delivered (i.e. COUNT(OrderPositions WHERE isDelivered = true) > 0).
#Entity
public class Order {
private long id;
private List<OrderPosition> orderPositions;
// ...
}
#Entity
public class OrderPosition {
private isDelivered = false;
// ...
}
(Code is simplified for readability.)

JOOQ: how do I add an interface to a generated Record Class

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.

Spring AOP for database operation

I am working in a spring,hibernate project and database is oracle. I have DAO layer for persistence related operations.
In all my tables, I have create_date and update_date columns representing the timestamp when a row is inserted and updated in the tables respectively.
There is a requirement that I have to update the above two mentioned timestamp columns of that particular table for which the request is meant to whenever any insert/update operation happens.For example, If my DAO layer has two methods, say m1 and m2 responsible for impacting t1 and t2 tables respectively. Now, if m1 method is invoked, then timestamp columns of t1 table will be updatedi.e. For insert, create_date column will be updated and for any update update_date column will be updated.
I have idea of Spring AOP so I was thinking to use AOP to implement the above requirement, though, i am not quite sure if it can be achieved using AOP.
Please let me know if I can use AOP to fulfill this requirement. And if it is possible, then please provide me the inputs how to implement it.
I have implemented update date feature for one of the modules in my application using Spring AOP.
PFB code for your reference
Hope this will help.
I wonder if one can have pointcuts for variable as well.I know its might not possible with spring's aspect j implementation.But any work around guys :P
**
* #author Vikas.Chowdhury
* #version $Revision$ Last changed by $Author$ on $Date$ as $Revision$
*/
#Aspect
#Component
public class UpdateDateAspect
{
#Autowired
private ISurveyService surveyService;
Integer surveyId = null;
Logger gtLogger = Logger.getLogger(this.getClass().getName());
#Pointcut("execution(* com.xyz.service.impl.*.saveSurvey*(..)))")
public void updateDate()
{
}
#Around("updateDate()")
public Object myAspect(final ProceedingJoinPoint pjp)
{
// retrieve the runtime method arguments (dynamic)
Object returnVal = null;
for (final Object argument : pjp.getArgs())
{
if (argument instanceof SurveyHelper)
{
SurveyHelper surveyHelper = (SurveyHelper) argument;
surveyId = surveyHelper.getSurveyId();
}
}
try
{
returnVal = pjp.proceed();
}
catch (Throwable e)
{
gtLogger.debug("Unable to use JointPoint :(");
}
return returnVal;
}
#After("updateDate()")
public void updateSurveyDateBySurveyId() throws Exception
{
if (surveyId != null)
{
surveyService.updateSurveyDateBySurveyId(surveyId);
}
}
}
I'd use an Hibernate interceptor instead, that's what they are for. For example, the entities that need such fields could implement the following interface:
public interface Auditable {
Date getCreated();
void setCreated(Date created);
Date getModified();
void setModified(Date modified);
}
Then the interceptor always sets the modified field on save, and only sets the created field when it's not already set.
Even though you have been asking for a Spring AOP solution to your question, I would like to point out that the same result can be achieved using database triggers, e. g. automatically setting the created timestamp during INSERT operations and the modified timestamp during UPDATE statements.
This may be a good solution, especially if not all your DB calls are going through the AOP-captured logic (e. g. when bypassing your pointcut definition because a method does not fit the pattern or even bypassing the code completely using a standalone SQL client), so that you could enforce the modified timestamp even when somebody updates the entries from a different application.
It would have the drawback that you need to define the triggers on all affected tables, though.
It should be possible with Spring AOP using a #Before advice. If you pass an entity to a create method have an advice set the create_date and for an update method the update_date. You may want to consider the following to make your job easier:
Have all entities implement a common interface to set create_date and update_date. This allows you to have a common advice without having to resort to reflection.
Have a naming convention to identify create and update methods on our DAOs. This will make your point cuts simpler.

Turning one annotation into many annotations with AspectJ

I have discovered a pattern in my JPA mappings that I would like to codify. A simple example follows:
#OneToMany(fetch=FetchType.EAGER)
#Sort(type=SortType.NATURAL)
private SortedSet<Item> items;
I would like to create a single annotation called SortedOneToMany that I can apply to the above set:
public #interface SortedOneToMany {
FetchType fetch() default EAGER;
SortType sort() default NATURAL;
Class comparator() default void.class;
}
I have written the following aspect to "attach" the JPA annotations whenever it sees my annotation:
public aspect SortedOneToManyAspect {
declare #field: #SortedOneToMany * * : #OneToMany(fetch=FetchType.EAGER);
declare #field: #SortedOneToMany * * : #Sort(type=SortType.NATURAL);
}
But I don't know how can I access the values of the SortedOneToMany annotation parameters and use them when defining the OneToMany and Sort annotations. There may be cases where I want to change one of the default values like so:
#SortedOneToMany(sort=SortType.COMPARATOR,comparator=ItemComparator.class)
private SortedSet<Item> items;
So how can I pass the annotation values from SortedOneToMany to the Sort annotation?
I received this answer from Andy Clement on the aspectj-users mailing list:
Hi,
I'm afraid you can't do that with AspectJ right now, you can't pass a
piece of the matched information to the new annotation. I can perhaps
imagine some hypothetical syntax:
declare #field:
#SortedOneToMany(sort=SortType.COMPARATOR,comparator={1}) * * :
#Sort(type=SortType.COMPARATOR,comparator={1});
which would seem to achieve what you want.
Maybe raise an enhancement request for it:
https://bugs.eclipse.org/bugs/enter_bug.cgi?product=AspectJ
sorry I don't have better news.
cheers
Andy
I created a ticket for the issue in case anyone wants to follow the progress: https://bugs.eclipse.org/bugs/show_bug.cgi?id=345515

How to return ids on Inserts with mybatis in mysql with annotations

See this related question for Postgres. For some reason, the solution doesn't work for me - the return value of the insert statement is always "1".
See this other question for an XML based solution. I would like to do the same without XML - insert a record and find the new auto-generated id of the record I just insreted.
I didn't find a matching annotation to <selectkey> (see this open issue)
How do I proceed?
Examining mybatis code reveals that INSERT is implemented via UPDATE, and always returns the number of inserted rows! So ... unless I'm completely missing something here, there's no way to do this using the current (3.0.3) implementation.
Actually, it's possible to do it, with the #Options annotation (provided you're using auto_increment or something similar in your database) :
#Insert("insert into table3 (id, name) values(null, #{name})")
#Options(useGeneratedKeys=true, keyProperty="idName")
int insertTable3(SomeBean myBean);
Note that the keyProperty="idName" part is not necessary if the key property in SomeBean is named "id". There's also a keyColumn attribute available, for the rare cases when MyBatis can't find the primary key column by himself. Please also note that by using #Options, you're submitting your method to some default parameters ; it's important to consult the doc (linked below -- page 60 in the current version) !
(Old answer) The (quite recent) #SelectKey annotation can be used for more complex key retrieval (sequences, identity() function...). Here's what the MyBatis 3 User Guide (pdf) offers as examples :
This example shows using the #SelectKey annotation to retrieve a value from a sequence before an
insert:
#Insert("insert into table3 (id, name) values(#{nameId}, #{name})")
#SelectKey(statement="call next value for TestSequence", keyProperty="nameId", before=true, resultType=int.class)
int insertTable3(Name name);
This example shows using the #SelectKey annotation to retrieve an identity value after an insert:
#Insert("insert into table2 (name) values(#{name})")
#SelectKey(statement="call identity()", keyProperty="nameId", before=false, resultType=int.class)
int insertTable2(Name name);
The <insert>, <update>and <delete> statements return the number of affected rows, as is common with database APIs.
If a new ID is generated for the inserted row, it is reflected in the object you passed as a parameter. So for example, if you call mapper.insert(someObject) inside your annotated insert method, after inserting, you can call someObject.getId (or similar) to retrieve it.
Using the options of <insert>, you can tweak how (by providing an SQL statement) and when (before or after the actual insertion) the id is generated or retrieved, and where in the object it is put.
It may be instructive to use the MyBatis generator to generate classes from a database schema and have a look at how inserts and updates are handled. Specifically, the generator produces "example" classes that are used as temporary containers to pass around data.
you can get your generated ids from save methods,
lets say a bean with ID and name properties,
bean.setName("xxx");
mapper.save(bean);
// here is your id
logger.debug(bean.getID);
I didn't like most of the answers I found online for returning generated keys because
All of the solutions I found called a "setter" on the inbound object
None of the solutions returned the generated column from the method
I came up with the following solution which addresses points 1 & 2 above which
Passes two parameters to mybatis "in" & "out" (mybatis does not mutate "in", it calls a setter on "out")
Requires an additional default method on the interface to return the value
public interface MyMapper {
/**
* this method is used by the mybatis mapper
* I don't call this method directly in my application code
*/
#Insert("INSERT INTO MY_TABLE (FOO) VALUES ({#in.foo})")
#Options(useGeneratedKeys=true, keyColumn="ID", keyProperty = "out.value")
void insert(#Param("in") MyTable in, #Param("out") LongReference out);
/**
* this "default method" is called in my application code and returns the generated id.
*/
default long insert(MyTable tableBean) {
LongReference idReference = new LongReference();
insert(tableBean, idReference);
return idReference.getValue();
}
}
This requires an additional class which can be re-used on similar methods in future
public class LongReference {
private Long value;
// getter & setter
}

Categories

Resources