Type mismatch: inferred type is () -> JoinColumn but JoinColumn was expected - spring

We are using Corda 4, Springboot web server and Postgresql 11.
Following are the versions of Corda platform, Springboot server, and other essential dependencies used-
cordaReleaseGroup=net.corda
cordaVersion=4.0
gradlePluginsVersion=4.0.45
kotlinVersion=1.2.71
junitVersion=4.12
quasarVersion=0.7.10
spring_version = '4.3.11.RELEASE'
spring_boot_version = '2.0.2.RELEASE'
spring_boot_gradle_plugin_version = '2.1.1.RELEASE'
jvmTarget = "1.8"
log4jVersion =2.11.2
platformVersion=4
slf4jVersion=1.7.25
nettyVersion=4.1.22.Final
We were able to achieve the sending of single transaction record to a target vault table, from a node to another.
We have come across a requirement in which the transaction is of One-to-many type, for which parent-child tables need to be created in the vault.
Following is the code to create the schema for the parent-child tables but it throws error on compilation -
"Type mismatch: inferred type is () -> JoinColumn but JoinColumn was expected".
import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentState
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
import java.util.UUID
object Schema1
object SchemaV1 : MappedSchema(
schemaFamily = Schema1.javaClass,
version = 1,
mappedTypes = listOf(PersistentEmployees::class.java,PersistentEmployeeVehicles::class.java))
{
#Entity
#Table(name = "TBL_EMPLOYEES")
class PersistentEmployees(
#Column(name = "EmployeeId")
var Pid: Long,
#Column(name = "EmployeeName")
var EmployeeName: String,
#Column(name = "EmployeeAddress")
var EmployeeAddress: String,
#OneToMany(cascade = [(CascadeType.PERSIST)])
#JoinColumns({
JoinColumn(name = "output_index", referencedColumnName = "output_index");
JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id") })
private val EmpVehicles:List<PersistentEmployeeVehicles>
) : PersistentState(), Serializable
#Entity
#Table(name = "TBL_EMPLOYEE_VEHICLES")
class PersistentEmployeeVehicles(
#Column(name = "ID")
var ID: UUID,
#Column(name = "VEHICLETYPE")
var VEHICLETYPE: String,
#Column(name = "VEHICLEMODEL")
var VEHICLEMODEL: String,
#Column(name = "VEHICLENUMBER")
var VEHICLENUMBER: String
)
}
Question 1: What would be the cause of the error and also the solution (if possible)?
We used "Car insurance" "One-to-many" mapping sample from Corda Git Hub. Following are the links-
"https://github.com/corda/samples/blob/release-V4/carinsurance-QueryableState/contracts/src/main/java/net/corda/examples/carinsurance/schema/PersistentInsurance.java"
"https://github.com/corda/samples/blob/release-V4/carinsurance-QueryableState/contracts/src/main/java/net/corda/examples/carinsurance/schema/PersistentClaim.java"

The syntax for declaring arrays within annotations is different between Java and Kotlin, for Kotlin, you should use [] like the following:
#JoinColumns(value = [
JoinColumn(name = "output_index", referencedColumnName = "output_index"),
JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id") ])
private val EmpVehicles:List<PersistentEmployeeVehicles>

Related

Hibernate detached entity passed to persist error in Spring Boot in Kotlin using OneToOne with MapsId

I have the following entities in a fairly simple and straightforward Spring Boot application in Kotlin:
#Entity
class Target(
#Id #GeneratedValue var id: Long? = null,
// ... other stuff
)
#Entity
class Ruleset(
#OneToOne(fetch = FetchType.LAZY) #MapsId
var target: Target,
#Id #GeneratedValue var id: Long? = null,
// ... other stuff
)
And I have the following code to create them upon startup of a #Component:
#PostConstruct
#Transactional
fun init() {
val target = Target()
targetRepository.save(target)
val rule = Ruleset(target)
rulesetRepository.save(rule)
}
And when this runs I get the "detached entity passed to persist: com.mystuff.Target" error. I've used this approach in the past (see here: https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/) without issue, although never in trying to create them at the same time in the same method. I've also tried using the entity passed back by the .save() call on the Target repository in the persist of the Ruleset object with no success.
I am able to fix this if I go back to the "normal" way of doing a OneToOne relationship:
#Entity
class Target(
#OneToOne(mappedBy = "target", cascade = [CascadeType.ALL],
fetch = FetchType.LAZY, optional = false)
var ruleset: Ruleset?
#Id #GeneratedValue var id: Long? = null
)
#Entity
class Ruleset(
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "target_id")
var target: Target,
#Id #GeneratedValue var id: Long? = null,
)
But this is annoying as it forces me to pass a null into the Target constructor and then update it immediately after creating the Ruleset. I can't figure out why the other, simpler approach doesn't work.

Spring Data JDBC Kotlin NoSuchMethod error: Dialect.getIdGeneration()

I'm writing a very simple Spring Data JDBC repository in Kotlin (using Postgres as the database):
data class Label(
#Id
#GeneratedValue
#Column( columnDefinition = "uuid", updatable = false )
val id: UUID,
val name: String
)
#Repository
interface LabelRepository: CrudRepository<Label, UUID> {}
When I do repository save:
val l = Label(id = UUID.randomUUID(), name = "name")
labelRepo.save(l)
It works fine. But since id is not null Spring Data JDBC will always treat it as an "update" to an existing label entity instead of creating a new one with generated ID.
So I changed id: UUID to id: UUID? And having val l = Label(id = null, name = "name")
But call the same save() method gives me:
java.lang.NoSuchMethodError: 'org.springframework.data.relational.core.dialect.IdGeneration org.springframework.data.relational.core.dialect.Dialect.getIdGeneration()'
I have tried a solution here: https://jivimberg.io/blog/2018/11/05/using-uuid-on-spring-data-jpa-entities/
But it didn't work, still gives me the same error
Wondering what's the cause of this and why this error pops up only when I change UUID to UUID??
nvm, turns out I have to use the implementation("org.springframework.boot:spring-boot-starter-data-jdbc") dependency instead of implementation("org.springframework.data:spring-boot-starter-data-jdbc:2.1.3")

Entity manager changes detached entities

Help me.
Why does the collection in the entity change after the transaction?
My entity:
#Entity
class Entity(
#Id
val uuid: UUID,
#OneToMany(cascade = [CascadeType.PERSIST, CascadeType.REMOVE])
#JoinTable(
name = "entities_items",
joinColumns = [JoinColumn(name = "entity_uuid")],
inverseJoinColumns = [JoinColumn(name = "item_uuid")]
)
val items: MutableList<Item>
)
My test:
#SpringBootTest
internal class EntityTest {
#Autowired
lateinit var entityRepository: EntityRepository
#Autowired
lateinit var transactionManager: PlatformTransactionManager
#Test
fun will_added_item() {
val entityBefore = entityRepository.findById(entityId).get()
// entityBefore.items.size == 0
TransactionTemplate(transactionManager).execute { _ ->
val entity = entityRepository.findById(entityId).get()
entity.items.add(item)
}
// entityBefore.items.size == 1 <-- ???
val entityAfter = entityRepository.findById(entityId).get()
}
}
Interestingly, if I add any call to the collection before the transaction, everything will be fine.
Spring Boot + Hibernate + JUnit
please ignore this wrong answer - can't seem to delete it on my phone!
This is because when you retrieve an item by id within a transaction multiple times, Hibernate will give you same object as it is managing the objects involved in the transaction as a unit of work.
Hence entityBefore and entity are pointing at the same object.
Ah sorry, ignore that - I see first retrieval was outside the tx!

Is #ManyToOne's "optional" param automatically set using Kotlin's nullability

I read that specifying optional = false in the #ManyToOne association annotation could help Spring improve the performance of the queries.
In a Kotlin data class entity, do I actually need to specify the parameter in the annotation, or can Spring figure this out by itself using the nullability of the item field?
For instance, if I have the following declaration:
#Entity
#Table(name = ACCESS_LOGS_ARCHIVES_TABLE, indexes = [
Index(name = "access_logs_archives_item_idx", columnList = "access_item_id")
])
data class AccessLogArchive(
val date: LocalDate,
#ManyToOne(optional = false)
#JoinColumn(name = "access_item_id", nullable = false)
val item: AccessLogItem,
val occurrences: Int
) {
#Id
#GeneratedValue
var id: Long? = null
}
#Entity
#Table(name = ACCESS_ITEMS_TABLE)
data class AccessLogItem(
#Column(length = 3) val code: String,
#Column(columnDefinition = "text") val path: String,
#Column(length = 10) val verb: String
) {
#Id
#GeneratedValue
var id: Long? = null
}
In this case, I would for instance expect Spring to know that the item field is not nullable, and thus the relationship should be understood as optional=false even without specifying it as I did. Is this the case?
Same question goes for the #JoinColumn's nullable = false, by the way.
Consider a simple entity like a Room which has a #ManyToOne relationship to House.
#Entity
class Room(
#ManyToOne(optional = true)
val house: House
) {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
val id: Long = 0
}
JPA will create a room table with a column
`house_id` bigint(20) DEFAULT NULL
If you specify #ManyToOne(optional = false)
the column will look like this:
`house_id` bigint(20) NOT NULL
By specifiying optional you tell JPA how the schema should be generated, whether the column can be NULL or not.
At runtime trying to load a Room without a House will cause an Exception if the house property is not nullable (House instead of House?) even when value of optional is true.
The same applies to #JoinColumn.
Is #ManyToOne's “optional” param automatically set using Kotlin's
nullability?
No it is not. It is independent from that and by default set to true.
Conclusion: In order for you schema to reflect your entities it is a good idea to use optional = true if the house property would be nullable and optional = false if the house property would be non-nullable.

Spring JPA Repository generating incorrect SQL

I'm using Spring JPA Repository with Hibernate below towards a MySQL Database. On that environment, I've the following Entity:
#Entity
#Table(name="cod__postales")
public class CodigoPostal {
#Id
#GeneratedValue
private Long registro;
#Column(name = "`POST_Nº_CODIGO`", length = 6, nullable = false)
private String codigo = " ";
#Column(name = "POST_DESCRIP", length = 30, nullable = false)
private String descripcion = " ";
#Column(name = "POST_ZONA_ASIG", length = 2, nullable = false)
private String zona = " ";
Also I've the following Spring JPA Repository:
public interface CodigoPostalRepository extends JpaRepository<CodigoPostal, Long> {
CodigoPostal findOneByCodigo(String codigo);
}
As you can see, there isan special character on the first column name 'º'. The problem es that, when I call to repo.findOneByCodigo() method, the following SQL is generated
select codigopost0_.registro as registro1_2_,
codigopost0_.`post_nº_codigo` as post_nº_2_2_,
codigopost0_.post_descrip as post_des3_2_,
codigopost0_.post_zona_asig as post_zon4_2_
from cod__postales codigopost0_
where codigopost0_.`post_nº_codigo`=?
The problem is that sql gives an error because of the name spring/hibernate assing to that column: as post_nº_2_2_.
How can I avoid this?
This is a first thought regarding this query and my suggestion is to introduce a native query which will help you to change 'as post_nº_2_2_.' in something like: 'as post_n_2_2_.'.
Example:
#Query(value = " select codigopost0_.registro as registro1_2_,
codigopost0_.`post_nº_codigo` as post_n_2_2_,
codigopost0_.post_descrip as post_des3_2_,
codigopost0_.post_zona_asig as post_zon4_2_
from cod__postales codigopost0_
where codigopost0_.`post_nº_codigo`=?", nativeQuery = true)
public interface CodigoPostalRepository extends JpaRepository<CodigoPostal, Long> {
CodigoPostal findOneByCodigo(String codigo);
}
More information on this link.
At the end I've been able to solve this by adding the characterEncoding parameter to the url string:
spring.datasource.url=jdbc:mysql://localhost/madr?characterEncoding=UTF-8
Anyway, I've opened an issue to Hibernate because maybe this is not a valid option for everyone https://hibernate.atlassian.net/browse/HHH-10493
Change
#Column(name = "`POST_Nº_CODIGO`", length = 6, nullable = false)
to
#Column(name = "`POST_N_CODIGO`", length = 6, nullable = false)

Resources