diff options
Diffstat (limited to 'opendc-web/opendc-web-server/src/main')
12 files changed, 17 insertions, 570 deletions
diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonType.kt b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/QuarkusObjectMapperSupplier.java index 9ee21a4c..e46c74ed 100644 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonType.kt +++ b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/QuarkusObjectMapperSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 AtLarge Research + * Copyright (c) 2023 AtLarge Research * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,29 +20,20 @@ * SOFTWARE. */ -package org.opendc.web.server.util.hibernate.json +package org.opendc.web.server.util; -import com.fasterxml.jackson.databind.ObjectMapper -import org.hibernate.type.AbstractSingleColumnStandardBasicType -import org.hibernate.type.BasicType -import org.hibernate.usertype.DynamicParameterizedType -import java.util.Properties -import javax.enterprise.inject.spi.CDI +import com.fasterxml.jackson.databind.ObjectMapper; +import io.hypersistence.utils.hibernate.type.util.ObjectMapperSupplier; +import io.quarkus.runtime.annotations.RegisterForReflection; +import javax.enterprise.inject.spi.CDI; /** - * A [BasicType] that contains JSON. + * A supplier for an {@link ObjectMapper} used by the Hypersistence utilities. */ -class JsonType(objectMapper: ObjectMapper) : AbstractSingleColumnStandardBasicType<Any>(JsonSqlTypeDescriptor, JsonTypeDescriptor(objectMapper)), DynamicParameterizedType { - /** - * No-arg constructor for Hibernate to instantiate. - */ - constructor() : this(CDI.current().select(ObjectMapper::class.java).get()) - - override fun getName(): String = "json" - - override fun registerUnderJavaType(): Boolean = true - - override fun setParameterValues(parameters: Properties) { - (javaTypeDescriptor as JsonTypeDescriptor).setParameterValues(parameters) +@RegisterForReflection +public class QuarkusObjectMapperSupplier implements ObjectMapperSupplier { + @Override + public ObjectMapper get() { + return CDI.current().select(ObjectMapper.class).get(); } } diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Job.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Job.kt index 84a71acf..9c260fc1 100644 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Job.kt +++ b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Job.kt @@ -23,9 +23,7 @@ package org.opendc.web.server.model import org.hibernate.annotations.Type -import org.hibernate.annotations.TypeDef import org.opendc.web.proto.JobState -import org.opendc.web.server.util.hibernate.json.JsonType import java.time.Instant import javax.persistence.Column import javax.persistence.Entity @@ -42,7 +40,6 @@ import javax.persistence.Table /** * A simulation job to be run by the simulator. */ -@TypeDef(name = "json", typeClass = JsonType::class) @Entity @Table(name = "jobs") @NamedQueries( @@ -103,7 +100,7 @@ class Job( /** * Experiment results in JSON */ - @Type(type = "json") + @Type(type = "io.hypersistence.utils.hibernate.type.json.JsonType") @Column(columnDefinition = "jsonb") var results: Map<String, Any>? = null diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Portfolio.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Portfolio.kt index 09437712..edf1205f 100644 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Portfolio.kt +++ b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Portfolio.kt @@ -23,9 +23,7 @@ package org.opendc.web.server.model import org.hibernate.annotations.Type -import org.hibernate.annotations.TypeDef import org.opendc.web.proto.Targets -import org.opendc.web.server.util.hibernate.json.JsonType import javax.persistence.CascadeType import javax.persistence.Column import javax.persistence.Entity @@ -45,7 +43,6 @@ import javax.persistence.UniqueConstraint /** * A portfolio is the composition of multiple scenarios. */ -@TypeDef(name = "json", typeClass = JsonType::class) @Entity @Table( name = "portfolios", @@ -85,7 +82,7 @@ class Portfolio( /** * The portfolio targets (metrics, repetitions). */ - @Type(type = "json") + @Type(type = "io.hypersistence.utils.hibernate.type.json.JsonType") @Column(columnDefinition = "jsonb", nullable = false, updatable = false) val targets: Targets ) { diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Scenario.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Scenario.kt index 62adc9e2..47c3e8b2 100644 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Scenario.kt +++ b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Scenario.kt @@ -23,9 +23,7 @@ package org.opendc.web.server.model import org.hibernate.annotations.Type -import org.hibernate.annotations.TypeDef import org.opendc.web.proto.OperationalPhenomena -import org.opendc.web.server.util.hibernate.json.JsonType import javax.persistence.CascadeType import javax.persistence.Column import javax.persistence.Embedded @@ -45,7 +43,6 @@ import javax.persistence.UniqueConstraint /** * A single scenario to be explored by the simulator. */ -@TypeDef(name = "json", typeClass = JsonType::class) @Entity @Table( name = "scenarios", @@ -101,7 +98,7 @@ class Scenario( @ManyToOne(optional = false) val topology: Topology, - @Type(type = "json") + @Type(type = "io.hypersistence.utils.hibernate.type.json.JsonType") @Column(columnDefinition = "jsonb", nullable = false, updatable = false) val phenomena: OperationalPhenomena, diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Topology.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Topology.kt index 26368455..fe48a0f2 100644 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Topology.kt +++ b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/model/Topology.kt @@ -23,9 +23,7 @@ package org.opendc.web.server.model import org.hibernate.annotations.Type -import org.hibernate.annotations.TypeDef import org.opendc.web.proto.Room -import org.opendc.web.server.util.hibernate.json.JsonType import java.time.Instant import javax.persistence.Column import javax.persistence.Entity @@ -43,7 +41,6 @@ import javax.persistence.UniqueConstraint /** * A datacenter design in OpenDC. */ -@TypeDef(name = "json", typeClass = JsonType::class) @Entity @Table( name = "topologies", @@ -86,7 +83,7 @@ class Topology( /** * Datacenter design in JSON */ - @Type(type = "json") + @Type(type = "io.hypersistence.utils.hibernate.type.json.JsonType") @Column(columnDefinition = "jsonb", nullable = false) var rooms: List<Room> = emptyList() ) { diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/AbstractJsonSqlTypeDescriptor.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/AbstractJsonSqlTypeDescriptor.kt deleted file mode 100644 index 9e29b734..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/AbstractJsonSqlTypeDescriptor.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.web.server.util.hibernate.json - -import org.hibernate.type.descriptor.ValueExtractor -import org.hibernate.type.descriptor.WrapperOptions -import org.hibernate.type.descriptor.java.JavaTypeDescriptor -import org.hibernate.type.descriptor.sql.BasicExtractor -import org.hibernate.type.descriptor.sql.SqlTypeDescriptor -import java.sql.CallableStatement -import java.sql.ResultSet -import java.sql.Types - -/** - * Abstract implementation of a [SqlTypeDescriptor] for Hibernate JSON type. - */ -internal abstract class AbstractJsonSqlTypeDescriptor : SqlTypeDescriptor { - - override fun getSqlType(): Int { - return Types.OTHER - } - - override fun canBeRemapped(): Boolean { - return true - } - - override fun <X> getExtractor(typeDescriptor: JavaTypeDescriptor<X>): ValueExtractor<X> { - return object : BasicExtractor<X>(typeDescriptor, this) { - override fun doExtract(rs: ResultSet, name: String, options: WrapperOptions): X { - return typeDescriptor.wrap(extractJson(rs, name), options) - } - - override fun doExtract(statement: CallableStatement, index: Int, options: WrapperOptions): X { - return typeDescriptor.wrap(extractJson(statement, index), options) - } - - override fun doExtract(statement: CallableStatement, name: String, options: WrapperOptions): X { - return typeDescriptor.wrap(extractJson(statement, name), options) - } - } - } - - open fun extractJson(rs: ResultSet, name: String): Any? { - return rs.getObject(name) - } - - open fun extractJson(statement: CallableStatement, index: Int): Any? { - return statement.getObject(index) - } - - open fun extractJson(statement: CallableStatement, name: String): Any? { - return statement.getObject(name) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonBinarySqlTypeDescriptor.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonBinarySqlTypeDescriptor.kt deleted file mode 100644 index df6a3013..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonBinarySqlTypeDescriptor.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.web.server.util.hibernate.json - -import com.fasterxml.jackson.databind.JsonNode -import org.hibernate.type.descriptor.ValueBinder -import org.hibernate.type.descriptor.WrapperOptions -import org.hibernate.type.descriptor.java.JavaTypeDescriptor -import org.hibernate.type.descriptor.sql.BasicBinder -import java.sql.CallableStatement -import java.sql.PreparedStatement - -/** - * A [AbstractJsonSqlTypeDescriptor] that stores the JSON as binary (JSONB). - */ -internal object JsonBinarySqlTypeDescriptor : AbstractJsonSqlTypeDescriptor() { - override fun <X> getBinder(typeDescriptor: JavaTypeDescriptor<X>): ValueBinder<X> { - return object : BasicBinder<X>(typeDescriptor, this) { - override fun doBind(st: PreparedStatement, value: X, index: Int, options: WrapperOptions) { - st.setObject(index, typeDescriptor.unwrap(value, JsonNode::class.java, options), sqlType) - } - - override fun doBind(st: CallableStatement, value: X, name: String, options: WrapperOptions) { - st.setObject(name, typeDescriptor.unwrap(value, JsonNode::class.java, options), sqlType) - } - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonBytesSqlTypeDescriptor.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonBytesSqlTypeDescriptor.kt deleted file mode 100644 index 4924f586..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonBytesSqlTypeDescriptor.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.web.server.util.hibernate.json - -import org.hibernate.type.descriptor.ValueBinder -import org.hibernate.type.descriptor.WrapperOptions -import org.hibernate.type.descriptor.java.JavaTypeDescriptor -import org.hibernate.type.descriptor.sql.BasicBinder -import java.io.UnsupportedEncodingException -import java.sql.CallableStatement -import java.sql.PreparedStatement -import java.sql.ResultSet -import java.sql.Types - -/** - * A [AbstractJsonSqlTypeDescriptor] that stores the JSON as UTF-8 encoded bytes. - */ -internal object JsonBytesSqlTypeDescriptor : AbstractJsonSqlTypeDescriptor() { - private val CHARSET = Charsets.UTF_8 - - override fun getSqlType(): Int { - return Types.BINARY - } - - override fun <X> getBinder(javaTypeDescriptor: JavaTypeDescriptor<X>): ValueBinder<X> { - return object : BasicBinder<X>(javaTypeDescriptor, this) { - override fun doBind(st: PreparedStatement, value: X, index: Int, options: WrapperOptions) { - st.setBytes(index, toJsonBytes(javaTypeDescriptor.unwrap(value, String::class.java, options))) - } - - override fun doBind(st: CallableStatement, value: X, name: String, options: WrapperOptions) { - st.setBytes(name, toJsonBytes(javaTypeDescriptor.unwrap(value, String::class.java, options))) - } - } - } - - override fun extractJson(rs: ResultSet, name: String): Any? { - return fromJsonBytes(rs.getBytes(name)) - } - - override fun extractJson(statement: CallableStatement, index: Int): Any? { - return fromJsonBytes(statement.getBytes(index)) - } - - override fun extractJson(statement: CallableStatement, name: String): Any? { - return fromJsonBytes(statement.getBytes(name)) - } - - private fun toJsonBytes(jsonValue: String): ByteArray? { - return try { - jsonValue.toByteArray(CHARSET) - } catch (e: UnsupportedEncodingException) { - throw IllegalStateException(e) - } - } - - private fun fromJsonBytes(jsonBytes: ByteArray?): String? { - return if (jsonBytes == null) { - null - } else { - try { - String(jsonBytes, CHARSET) - } catch (e: UnsupportedEncodingException) { - throw IllegalStateException(e) - } - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonSqlTypeDescriptor.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonSqlTypeDescriptor.kt deleted file mode 100644 index bd22ffbe..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonSqlTypeDescriptor.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.web.server.util.hibernate.json - -import org.hibernate.dialect.H2Dialect -import org.hibernate.dialect.PostgreSQL81Dialect -import org.hibernate.internal.SessionImpl -import org.hibernate.type.descriptor.ValueBinder -import org.hibernate.type.descriptor.ValueExtractor -import org.hibernate.type.descriptor.WrapperOptions -import org.hibernate.type.descriptor.java.JavaTypeDescriptor -import org.hibernate.type.descriptor.sql.BasicBinder -import org.hibernate.type.descriptor.sql.BasicExtractor -import org.hibernate.type.descriptor.sql.SqlTypeDescriptor -import java.sql.CallableStatement -import java.sql.PreparedStatement -import java.sql.ResultSet -import java.sql.Types - -/** - * A [SqlTypeDescriptor] that automatically selects the correct implementation for the database dialect. - */ -internal object JsonSqlTypeDescriptor : SqlTypeDescriptor { - - override fun getSqlType(): Int = Types.OTHER - - override fun canBeRemapped(): Boolean = true - - override fun <X> getExtractor(javaTypeDescriptor: JavaTypeDescriptor<X>): ValueExtractor<X> { - return object : BasicExtractor<X>(javaTypeDescriptor, this) { - private var delegate: AbstractJsonSqlTypeDescriptor? = null - - override fun doExtract(rs: ResultSet, name: String, options: WrapperOptions): X { - return javaTypeDescriptor.wrap(delegate(options).extractJson(rs, name), options) - } - - override fun doExtract(statement: CallableStatement, index: Int, options: WrapperOptions): X { - return javaTypeDescriptor.wrap(delegate(options).extractJson(statement, index), options) - } - - override fun doExtract(statement: CallableStatement, name: String, options: WrapperOptions): X { - return javaTypeDescriptor.wrap(delegate(options).extractJson(statement, name), options) - } - - private fun delegate(options: WrapperOptions): AbstractJsonSqlTypeDescriptor { - var delegate = delegate - if (delegate == null) { - delegate = resolveSqlTypeDescriptor(options) - this.delegate = delegate - } - return delegate - } - } - } - - override fun <X> getBinder(javaTypeDescriptor: JavaTypeDescriptor<X>): ValueBinder<X> { - return object : BasicBinder<X>(javaTypeDescriptor, this) { - private var delegate: ValueBinder<X>? = null - - override fun doBind(st: PreparedStatement, value: X, index: Int, options: WrapperOptions) { - delegate(options).bind(st, value, index, options) - } - - override fun doBind(st: CallableStatement, value: X, name: String, options: WrapperOptions) { - delegate(options).bind(st, value, name, options) - } - - private fun delegate(options: WrapperOptions): ValueBinder<X> { - var delegate = delegate - if (delegate == null) { - delegate = checkNotNull(resolveSqlTypeDescriptor(options).getBinder(javaTypeDescriptor)) - this.delegate = delegate - } - return delegate - } - } - } - - /** - * Helper method to resolve the appropriate [SqlTypeDescriptor] based on the [WrapperOptions]. - */ - private fun resolveSqlTypeDescriptor(options: WrapperOptions): AbstractJsonSqlTypeDescriptor { - val session = options as? SessionImpl - return when (session?.jdbcServices?.dialect) { - is PostgreSQL81Dialect -> JsonBinarySqlTypeDescriptor - is H2Dialect -> JsonBytesSqlTypeDescriptor - else -> JsonStringSqlTypeDescriptor - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonStringSqlTypeDescriptor.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonStringSqlTypeDescriptor.kt deleted file mode 100644 index 6e015762..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonStringSqlTypeDescriptor.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.web.server.util.hibernate.json - -import org.hibernate.type.descriptor.ValueBinder -import org.hibernate.type.descriptor.WrapperOptions -import org.hibernate.type.descriptor.java.JavaTypeDescriptor -import org.hibernate.type.descriptor.sql.BasicBinder -import java.sql.CallableStatement -import java.sql.PreparedStatement -import java.sql.ResultSet -import java.sql.Types - -/** - * A [AbstractJsonSqlTypeDescriptor] that stores the JSON as string (VARCHAR). - */ -internal object JsonStringSqlTypeDescriptor : AbstractJsonSqlTypeDescriptor() { - override fun getSqlType(): Int = Types.VARCHAR - - override fun <X> getBinder(typeDescriptor: JavaTypeDescriptor<X>): ValueBinder<X> { - return object : BasicBinder<X>(typeDescriptor, this) { - override fun doBind(st: PreparedStatement, value: X, index: Int, options: WrapperOptions) { - st.setString(index, typeDescriptor.unwrap(value, String::class.java, options)) - } - - override fun doBind(st: CallableStatement, value: X, name: String, options: WrapperOptions) { - st.setString(name, typeDescriptor.unwrap(value, String::class.java, options)) - } - } - } - - override fun extractJson(rs: ResultSet, name: String): Any? { - return rs.getString(name) - } - - override fun extractJson(statement: CallableStatement, index: Int): Any? { - return statement.getString(index) - } - - override fun extractJson(statement: CallableStatement, name: String): Any? { - return statement.getString(name) - } -} diff --git a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonTypeDescriptor.kt b/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonTypeDescriptor.kt deleted file mode 100644 index 9407f940..00000000 --- a/opendc-web/opendc-web-server/src/main/kotlin/org/opendc/web/server/util/hibernate/json/JsonTypeDescriptor.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2022 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.opendc.web.server.util.hibernate.json - -import com.fasterxml.jackson.databind.ObjectMapper -import org.hibernate.HibernateException -import org.hibernate.annotations.common.reflection.XProperty -import org.hibernate.annotations.common.reflection.java.JavaXMember -import org.hibernate.engine.jdbc.BinaryStream -import org.hibernate.engine.jdbc.internal.BinaryStreamImpl -import org.hibernate.type.descriptor.WrapperOptions -import org.hibernate.type.descriptor.java.AbstractTypeDescriptor -import org.hibernate.type.descriptor.java.BlobTypeDescriptor -import org.hibernate.type.descriptor.java.DataHelper -import org.hibernate.type.descriptor.java.MutableMutabilityPlan -import org.hibernate.usertype.DynamicParameterizedType -import java.io.ByteArrayInputStream -import java.io.IOException -import java.io.InputStream -import java.lang.reflect.Type -import java.sql.Blob -import java.sql.SQLException -import java.util.Objects -import java.util.Properties - -/** - * An [AbstractTypeDescriptor] implementation for Hibernate JSON type. - */ -internal class JsonTypeDescriptor(private val objectMapper: ObjectMapper) : AbstractTypeDescriptor<Any>(Any::class.java, JsonMutabilityPlan(objectMapper)), DynamicParameterizedType { - private var type: Type? = null - - override fun setParameterValues(parameters: Properties) { - val xProperty = parameters[DynamicParameterizedType.XPROPERTY] as XProperty - type = if (xProperty is JavaXMember) { - val x = xProperty as JavaXMember - x.javaType - } else { - (parameters[DynamicParameterizedType.PARAMETER_TYPE] as DynamicParameterizedType.ParameterType).returnedClass - } - } - - override fun areEqual(one: Any?, another: Any?): Boolean { - return when { - one === another -> true - one == null || another == null -> false - one is String && another is String -> one == another - one is Collection<*> && another is Collection<*> -> Objects.equals(one, another) - else -> areJsonEqual(one, another) - } - } - - override fun toString(value: Any?): String { - return objectMapper.writeValueAsString(value) - } - - override fun fromString(string: String): Any? { - return objectMapper.readValue(string, objectMapper.typeFactory.constructType(type)) - } - - override fun <X> unwrap(value: Any?, type: Class<X>, options: WrapperOptions): X? { - if (value == null) { - return null - } - - @Suppress("UNCHECKED_CAST") - return when { - String::class.java.isAssignableFrom(type) -> toString(value) - BinaryStream::class.java.isAssignableFrom(type) || ByteArray::class.java.isAssignableFrom(type) -> { - val stringValue = if (value is String) value else toString(value) - BinaryStreamImpl(DataHelper.extractBytes(ByteArrayInputStream(stringValue.toByteArray()))) - } - Blob::class.java.isAssignableFrom(type) -> { - val stringValue = if (value is String) value else toString(value) - BlobTypeDescriptor.INSTANCE.fromString(stringValue) - } - Any::class.java.isAssignableFrom(type) -> toJsonType(value) - else -> throw unknownUnwrap(type) - } as X - } - - override fun <X> wrap(value: X?, options: WrapperOptions): Any? { - if (value == null) { - return null - } - - var blob: Blob? = null - if (Blob::class.java.isAssignableFrom(value.javaClass)) { - blob = options.lobCreator.wrap(value as Blob?) - } else if (ByteArray::class.java.isAssignableFrom(value.javaClass)) { - blob = options.lobCreator.createBlob(value as ByteArray?) - } else if (InputStream::class.java.isAssignableFrom(value.javaClass)) { - val inputStream = value as InputStream - blob = try { - options.lobCreator.createBlob(inputStream, inputStream.available().toLong()) - } catch (e: IOException) { - throw unknownWrap(value.javaClass) - } - } - - val stringValue: String = try { - if (blob != null) String(DataHelper.extractBytes(blob.binaryStream)) else value.toString() - } catch (e: SQLException) { - throw HibernateException("Unable to extract binary stream from Blob", e) - } - - return fromString(stringValue) - } - - private class JsonMutabilityPlan(private val objectMapper: ObjectMapper) : MutableMutabilityPlan<Any>() { - override fun deepCopyNotNull(value: Any): Any { - return objectMapper.treeToValue(objectMapper.valueToTree(value), value.javaClass) - } - } - - private fun readObject(value: String): Any { - return objectMapper.readTree(value) - } - - private fun areJsonEqual(one: Any, another: Any): Boolean { - return readObject(objectMapper.writeValueAsString(one)) == readObject(objectMapper.writeValueAsString(another)) - } - - private fun toJsonType(value: Any?): Any { - return try { - readObject(objectMapper.writeValueAsString(value)) - } catch (e: Exception) { - throw IllegalArgumentException(e) - } - } -} diff --git a/opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties b/opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties new file mode 100644 index 00000000..451ce2d8 --- /dev/null +++ b/opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties @@ -0,0 +1 @@ +hypersistence.utils.jackson.object.mapper=org.opendc.web.server.util.QuarkusObjectMapperSupplier |
