How to conditionally include a Hibernate annotation?

hibernate conditional join
custom sequence generator in jpa
hibernate @where vs filter
hibernate column transformer example
hibernate filter

I have the code below in Play for Scala to access a SAP Hana table with Hibernate. I need to implement the same code with MySql, but the problem is that MySql doesn't support sequences (it works with AUTO_INCREMENT columns) and the code breaks because I have to specify @SequenceGenerator for Hana. Is there a way to compile this code with a condition to exclude the @SequenceGenerator annotation, so it works for MySql and Hana at the same time?

@Entity
@Table(name = "clients")
class ClientJpa {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
    @SequenceGenerator(name="generator", sequenceName = "cliSeq", allocationSize = 1)    
    var surrogateKey: Int = _
    var code: String = _
    var name: String = _
}

This answer attempts to implement Eugene's suggestion (so if it works please give credit to Eugene).

Given the following definition of @ifNotMysql macro

import scala.reflect.macros.blackbox
import scala.language.experimental.macros
import scala.annotation.{StaticAnnotation, compileTimeOnly}

object ifNotMysqlMacro {
  val targetIsMySql = sys.props.get("target-mysql").contains("true")

  def impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._

    def mysqlAnnots(annotations: Seq[c.universe.Tree]): Seq[c.universe.Tree] =
      annotations
        .filterNot(_.toString.contains("SequenceGenerator"))
        .filterNot(_.toString.contains("GeneratedValue"))
        .:+(q"""new GeneratedValue(strategy = GenerationType.IDENTITY)""")

    val result = annottees.map(_.tree).toList match {
      case q"@..$annots var $pat: $tpt = $expr" :: Nil =>
        q"""
            @..${if (targetIsMySql) mysqlAnnots(annots) else annots}
            var $pat: $tpt = $expr
          """
    }
    c.Expr[Any](result)
  }
}

@compileTimeOnly("enable macro paradise to expand macro annotations")
class ifNotMysql extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro ifNotMysqlMacro.impl
}

if we write @ifNotMysql @GeneratedValue(...) @SequenceGenerator like so

@ifNotMysql 
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
@SequenceGenerator(name="generator", sequenceName = "cliSeq", allocationSize = 1)    
var surrogateKey: Int = _

and provide system property target-mysql like so

sbt -Dtarget-mysql=true compile

then @SequenceGenerator annotation will be excluded and @GeneratedValue(strategy = GenerationType.IDENTITY) added like so

@GeneratedValue(strategy = GenerationType.IDENTITY)
var surrogateKey: Int = _

This implementation is based on scalamacros/sbt-example-paradise

How to Implement Conditional Auditing with Hibernate Envers, How to Implement Conditional Auditing with Hibernate Envers It will then document all insert, update and delete operations and you can even code snippet, I annotated this entity with @Audited so that Hibernate Envers audits all changes. Probably not what you want to hear but AFAIK there's no way to conditionally include annotations. An alternative would be to include the common functionality in a @MappedSuperclass and inject the concrete instance as appropriate at build time depending on the environment.

Probably not what you want to hear but AFAIK there's no way to conditionally include annotations. An alternative would be to include the common functionality in a @MappedSuperclass and inject the concrete instance as appropriate at build time depending on the environment. Something like this:-

@MappedSuperclass
abstract class AbstractClientJpa {
    var surrogateKey: Int   // abstract
    var code: String = _
    var name: String = _
}

...

@Entity
@Table(name = "clients")
class HanaClientJpa extends AbstractClientJpa {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
    @SequenceGenerator(name="generator", sequenceName = "cliSeq", allocationSize = 1)    
    var surrogateKey: Int = _
}

...

@Entity
@Table(name = "clients")
class MySQLClientJpa extends AbstractClientJpa {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var surrogateKey: Int = _
}

Getting started with Spring Framework: covers Spring 5 (4th Edition), annotation to conditionally include environment • the application should support both Hibernate and MyBatis ORM frameworks for database interaction. Using this filter definition name, we enable filter by Session enableFilter() method and disable it by disableFilter() method. To apply filter on entity load we use @Filter and on collection load we need to use @FilterJoinTable on association. Hibernate filter is created and used by below annotations and methods.

Assuming I understand your problem correctly I have 2 potential solutions for you. Both are general ideas and you'll have to do some legwork to actually implement them.

  1. Use macros. Here is a bit old article that does some AST manipulation to enrich case classes. You should be able to do something in that vein for your case. Here is a way pass parameters to your macro at compile time. Main con with this route is that macro api was scala version dependent, somewhat messy, unstable and hard to find good documentation for last time I checked.

  2. Use AspectJ. You should be able to declare annotations you need on classes in build-time. Main con here is that you'll have to add AspectJ weaving to your build which may or may not be easy.

Hibernate Search 5.11.5.Final: Reference Guide, To achieve this you have to add a few annotations to the Book and Author class. The first annotation @Indexed marks Book as indexable. By design Hibernate  The answer is covered behind the Hibernate‘s annotation @Where. Let’s consider how we can decorate an entity with the @Where annotation to avoid extra condition in regular SQL queries:

I think the way to do it is to provide a custom IdGeneratorStrategyInterpreter and register it using MetadataBuilder.applyIdGenerationTypeInterpreter. In your custom IdGeneratorStrategyInterpreter you can override determineGeneratorName to return "identity" constant for GenerationType.SEQUENCE if you know that the code is run against MySql and return null in all other cases to let the FallbackInterpreter do its default job (the string "identity" also comes from FallbackInterpreter.determineGeneratorName implementation). And you can do nothing in other methods and let the FallbackInterpreter do it's usual job.

P.S. Please also note that Hibernate's default SequenceStyleGenerator is actually aware of DBs not supporting "sequences" (exposed via Dialect.supportsSequences) and is able to emulate similar behavior using additional table. This might or might not be OK for your scenario.

Hibernate Validator 6.1.4.Final, Hibernate Validator annotation processor: org.hibernate.validator. The key of the invalid element is included in the property path (in the second This allows to define error messages based on conditional logic and also  This Spring tutorial is to learn about @Conditional annotation that was introduced in Spring 4.0 We shall see about what @Conditional annotation is, in what scenarios it can be used, difference between @Conditional vs @Profile annotations and an example Spring application using @Conditional annotation.

If ID in mysql is given auto-increment then in hibernate mapping ID should be IDENTITY

Replace that with

@Entity
@Table(name="clients")
class ClientJpa{
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "generator")
  var surrogateKey: Int = _
  var code: String = _
  var name: String = _

 }

Hope it works....

Spring @Conditional Annotation, When this condition fails (that is ELSE block in “IF-ELSE” conditional checking), Spring IOC Container does not load “employee” bean into Spring  Hibernate one to many mapping is made between two entities where first entity can have relation with multiple second entity instances but second can be associated with only one instance of first entity. Its 1 to N relationship. For example, in any company an employee can register multiple bank accounts but one bank account will be associated

A Custom Auto-Configuration with Spring Boot, Simply put, the Spring Boot autoconfiguration represents a way to marked with @Conditional annotations so that the auto-configuration or specific We can add the Hibernate specific properties to the mysql.properties file:. Named queries in hibernate is a technique to group the HQL statements in single location, and lately refer them by some name whenever need to use them. It helps largely in code cleanup because these HQL statements are no longer scattered in whole code. Apart from above, below are some minor advantages of named queries: …

Dynamic Mapping with Hibernate, Explore dynamic mapping capabilities of Hibernate with the Note that although Hibernate implements the JPA specification, annotations described here Hibernate is smart enough to parse the SQL we provided and insert  Hibernate Insert Query Tutorial By Lokesh Gupta | Filed Under: Hibernate Hibernate is an object-relational mapping (ORM) library for the Java language, providing a framework for mapping an object-oriented domain model to a traditional relational database.

Hibernate Community • View topic, The JPA annotation does not support this feature, and you should not is heavy load on the application hibernate inserting duplicate rows with 

Comments
  • I have the same problem did you find a solution?
  • @GeneratedValue also needs to change depending on whether the compilation is on Hana or MySql, it seems that your solution handles only @SequenceGenerator
  • If environment is MySql then the following line should be inserted instead of the one in the example: @GeneratedValue(strategy = GenerationType.IDENTITY)
  • Mario, inserting a row in MySQL throws an error, are you sure it's replacing with GenerationType.IDENTITY when MySQL is set?
  • @ps0604 What is the error? Perhaps it is because I did not provide generator argument to @GeneratedValue, that is, @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "generator"). I have edited the answer, please try again.
  • By the way, if I compile in MySQL removing Hana annotations, this works fine with @GeneratedValue(strategy = GenerationType.IDENTITY) and without the generator argument.
  • I have attempted to implement your suggestion and provided it as an answer. I hope that is ok. If not feel free to paste the code in your answer and I could remove mine. stackoverflow.com/questions/47995473/…
  • @MarioGalic I am ok with this.