Corda: InstantiationException when extending FungibleState in custom Schema - jpa

This issue is similar to the one posted here: Corda: error=org.hibernate.InstantiationException: No default constructor for entity
I am getting the same error for a custom schema extending FungibleState (as described in the API Vault Query documentation):
object CustomSchemaV1 : MappedSchema(schemaFamily = CustomSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCustomState::class.java))
{
#Entity
#Table(name = "custom_states", indexes = arrayOf(Index(name = "custom_field_idx", columnList = "custom_field")))
class PersistentCustomState(
/** Custom attributes */
#Column(name = "custom_field")
var customField: String? = null,
/** FungibleState parent attributes */
#Transient
val _participants: Set<AbstractParty>,
#Transient
val _owner: AbstractParty,
#Transient
val _quantity: Long,
#Transient
val _issuerParty: AbstractParty,
#Transient
val _issuerRef: OpaqueBytes
) : CommonSchemaV1.FungibleState(_participants?.toMutableSet(), _owner, _quantity, _issuerParty, _issuerRef.bytes)}
Example schema found here: https://github.com/corda/corda/blob/master/finance/src/test/kotlin/net/corda/finance/schemas/SampleCashSchemaV2.kt
I have the kotlin-jpa plugin installed. Making all fields nullable seems to solve the issue for schemas extending PersistentState, but is not an option here because of the FungibleState parent field data types.
Corda release version = 2.0.0

You need to add a default constructor to the body of PersistentCustomState. Something like:
constructor() : this(*first default value*, *second default value*, etc.)
The difficulty will be in passing default values for the AbstractParty parameters. You can use something like:
AnonymousParty(generateKeyPair().public)

Related

jooq deserialize a polymorphic class

I am using JOOQ to manipulate the database,now i have a problem.
There is a polymorphic class OrderEntry
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", visible = true)
#JsonSubTypes(value = {
#JsonSubTypes.Type(value = ReissueOrderEntry.class, name = "reissue"),
#JsonSubTypes.Type(value = RawOrderEntry.class, name = "raw"),
#JsonSubTypes.Type(value = FreebieOrderEntry.class, name = "freebie"),
#JsonSubTypes.Type(value = ReplaceOrderEntry.class, name = "replace")
})
public class OrderEntry extends OrderObject {
String type;
}
It will be deserialized into different objects according to the field 'type'.
But in jooq's deserialization it will only be deserialized as OrderEntry.
code
How can i solve it?
I'm assuming you're trying to use the built-in ConverterProvider logic that makes use of Jackson, e.g. when writing things like:
record.into(OrderEntry.class);
jOOQ loads Jackson from the classpath without any additional modules / plugins loaded. If you wish to use additional plugins, then you'll have to roll your own ConverterProvider, which implements loading additional plugins.

Using uuid[] type in Postgres with kotlin and hibernate

I'm pretty new to Kotlin and whole JVM world and I'm trying to figure out how should I use that type. I was trying to implement it as mentioned in this tutorial: https://medium.com/#sajithvijesekar/spring-jpa-data-with-postgres-array-types-a6cc4be421e2 but as a result I received: No Dialect mapping for JDBC type: 2003 during app startup. I wanted to use that field in entity this way:
#Entity
class Model(#field:Id val id: UUID, var name: String) {
#Column
#Type(type = "com.dal.type.GenericArrayUserType")
private val tagsProjection = arrayOf<UUID>()
}
Is that error related with way how I use it in my model?
Ok, I know what I was doing wrong. I haven't included #Column(columnDefinition = "uuid[]") in my Entity

How to make a data class in Kotlin immutable with java Date object in it?

The java.util.Date itself is a mutable object. As such even if Kotlin data class (with date field declared val) prevents me from changing the reference I can modify the date object itself to change its value.
Ways I could come up with:
Use normal class, override getter and setter. In each use the clone method to make a copy of given date.
#Column(name = "db_date")
private var dbDate: Date? = null
get() = dbDate?.clone() as Date
set(date) {
field = date?.clone() as Date
}
Also I can't use the copy method of data class since these classes are hibernate entities. So I need to modify them via setters.
The reason I want to use data classes for my entities is because these implement equals and hashcode by default. We had been using lombok in java for this and now convincing team to create these methods is tough. Even if generation happens by IDE its still going to be checked into source control.
So is there any way I could do custom setters on data class logic. Or any way I can generate equals and hashcode for normal classes without checking them in source control?
Edit: In comments it was pointed out to use java.time.Instant which is Immutable. The issue I am faced with is that this is a Hibernate Entity Class and we are using hibernate 3.6. Instant support came in hibernate 5.2 so we are way behind and migration of hibernate will be a heavy task. What I did notice is that kotlin data classes do allow setters and getters just in a different way. Code below:
#Entity
#Table(name = "my_table")
data class MyTable(
#Id
#Column(name = "id")
var id: Long? = null,
#Column(name = "my_date")
private var date: Date? = null,
) {
fun getDate():Date = gradedDate?.clone() as Date
fun setDate(date: Date?) {
this.date = date?.clone() as Date
}
}
You can do it with some hack:
#Entity
#Table(name = "my_table")
data class DateWrapper(
#Id
#Column(name = "id")
val id: Long?,
#Column(name = "my_date")
private var _date: Date?
) {
init {
_date = _date?.clone() as Date
}
val date = _date
}
Try using java.sql.Date instead

JPA and "anonymous" classes in scala

I'm a bit stuck and don't understand what's going on.
This one doesn't work
#Entity
#DynamicInsert
#DynamicUpdate
#SelectBeforeUpdate
#Table
class Entity {
#Column(nullable = false)
var owner: String = _
}
val myEntity = new Entity() {
owner = "some owner 1"
}
session.persist(myEntity)
Hibernate throws exception:
java.lang.IllegalArgumentException: Unknown entity:persistence.dao.EntityDaoTest$$anonfun$13$$anonfun$14$$anon$5
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:777)
This one works:
val myEntity = new Entity()
entity.owner = "some owner 1"
session.persist(myEntity)
Why? Why does hibernate don't recognize my Entity instance?
UPD:
#Sheinbergon, thanks, it's clear. I completely forgot that annotations are lost. Is there any possibility to set entity fields with some shortcut?
writing
val myEntity = new MyEntity()
myEntity.owner = "some owner"
myEntity.someOtherProperty = "value"
is super boring
One more question
This one works:
val parent = new Parent
parent.owner = "Our parent"
parent.addChild(new Child() {
name = "First parent's child"
addGrandChild(new GrandChild() {
name = "Grand child name"
addGrandGrandChild(new GrandGrandChild() {
name = "Grand Grand child name"
address = new Address() {
id = 1L
}
})
})
})
Why? Child, GrandChild, GrandGrandChild also created anonymously.
addChild, addGrandChild, addGrandGrandChild are just list mutators.
def addChild(child: Child): Unit = {
if (children == null) {
children = new util.ArrayList[Child]()
}
if (Option(child.parent).isEmpty) {
child.parent = this
}
children.add(child)
}
What you are doing here is instantiating a class anonymously in Scala , and well... that creates an anonymous implementation of your class Entity ( like instantiating an interface anonymously in Java).
you can see it by printing the class name - println(myEntity.getClass) in both cases
Annotations applied to the original class do not apply to the anonymous one (reflection can still find them in the super class, but that's up to the code scanning them) and I guess that's why you're getting the various JPA exceptions
In response to your added sub-questions
Regarding a shortcut - why don't you use companion objects for factories or turn this class into a case class (with defaults), allowing for nicer, more flexible initialization.
Regarding the second object graph(and assuming eachof your classes are annotated) - again it depends on how the reflective code treats the objects it scans. it's possible ( and more likely, given that it won't scan each member of the collection for annotations ) it takes annotation definitions from the erased type ( possible to get it's FQDN class name as ParameterizedType in Java's reflection API) of the collection and not from the actual members of the collection and that's why it works.
I'm not really sure what it does about field definitions though (they are only present in the "super" class), but there's no "magic" here, just plain old reflection scans.

Defining indices independently for same field in child and parent documents in different collections

I have two classes that look like this:
#Document(collection = 'rule')
class Rule {
#Indexed(unique = true)
String name
}
#Document(collection = 'archived_rule')
class ArchivedRule extends Rule {
#Indexed(unique = false)
String name
}
Rules are the primary domain class that my application works with. Only the latest version of each Rule is stored in the 'rule' collection. When a Rule is updated, a copy of it is made and is saved in the 'archived_rule' collection.
The name field should be unique in the 'rule' collection. It should be able to have duplicates in the 'archived_rule' collection.
Defining my classes as I have above does not seem to work. When I start my application, I get an exception like this:
Caused by: org.springframework.data.mapping.model.MappingException: Ambiguous field mapping detected! Both #org.springframework.data.mongodb.core.index.Indexed(expireAfterSeconds=-1, dropDups=false, sparse=false, useGeneratedName=false, background=false, unique=true, name=, collection=, direction=ASCENDING) private java.lang.String ...Rule.name and #org.springframework.data.mongodb.core.index.Indexed(expireAfterSeconds=-1, dropDups=false, sparse=false, useGeneratedName=false, background=false, unique=false, name=, collection=, direction=ASCENDING) private java.lang.String ...ArchivedRule.name map to the same field name name! Disambiguate using #Field annotation!
I have also tried not specifying the name field at all in the ArchivedRule class, but in that case it creates a unique index on the 'name' field in the 'archived_rule' collection.
I have thought that I could make Rule and ArchivedRule unrelated by inheritance and then explicitly re-define all the fields I need to save from Rule in ArchivedRule. I would like to avoid having to do that, though.
Is there some other way that I can specify my classes so that Rule.name has a unique index and ArchivedRule.name does not have a unique index?
I was able to solve this by adding an abstract base class with the shared fields other than name that both Rule and ArchivedRule extend from. They each then define their own version of name with the appropriate index configuration.
class RuleBase {
String sharedField
}
#Document(collection = 'rule')
class Rule extends RuleBase {
#Indexed(unique = true)
String name
}
#Document(collection = 'archived_rule')
class ArchivedRule extends RuleBase {
#Indexed(unique = false)
String name
}