diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java index 77882c8f83..4f8c0f9e45 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java @@ -21,6 +21,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.device.data.DeviceData; import org.thingsboard.server.common.data.id.CustomerId; @@ -31,6 +32,7 @@ import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.server.dao.util.mapping.JsonBinaryType; import org.thingsboard.server.dao.util.mapping.JsonStringType; import javax.persistence.Column; @@ -39,7 +41,10 @@ import java.util.UUID; @Data @EqualsAndHashCode(callSuper = true) -@TypeDef(name = "json", typeClass = JsonStringType.class) +@TypeDefs({ + @TypeDef(name = "json", typeClass = JsonStringType.class), + @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class) +}) @MappedSuperclass public abstract class AbstractDeviceEntity extends BaseSqlEntity implements SearchTextEntity { @@ -68,8 +73,8 @@ public abstract class AbstractDeviceEntity extends BaseSqlEnti @Column(name = ModelConstants.DEVICE_DEVICE_PROFILE_ID_PROPERTY, columnDefinition = "uuid") private UUID deviceProfileId; - @Type(type = "json") - @Column(name = ModelConstants.DEVICE_DEVICE_DATA_PROPERTY) + @Type(type = "jsonb") + @Column(name = ModelConstants.DEVICE_DEVICE_DATA_PROPERTY, columnDefinition = "jsonb") private JsonNode deviceData; public AbstractDeviceEntity() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceEntity.java index 0c91225b74..15c2c00b36 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceEntity.java @@ -18,8 +18,10 @@ package org.thingsboard.server.dao.model.sql; import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.dao.model.ModelConstants; +import org.thingsboard.server.dao.util.mapping.JsonBinaryType; import org.thingsboard.server.dao.util.mapping.JsonStringType; import javax.persistence.Entity; @@ -28,7 +30,10 @@ import javax.persistence.Table; @Data @EqualsAndHashCode(callSuper = true) @Entity -@TypeDef(name = "json", typeClass = JsonStringType.class) +@TypeDefs({ + @TypeDef(name = "json", typeClass = JsonStringType.class), + @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class) +}) @Table(name = ModelConstants.DEVICE_COLUMN_FAMILY_NAME) public final class DeviceEntity extends AbstractDeviceEntity { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java index fa481e1f80..27e77d4eca 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java @@ -32,7 +32,7 @@ import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; import org.thingsboard.server.dao.util.mapping.JacksonUtil; -import org.thingsboard.server.dao.util.mapping.JsonStringType; +import org.thingsboard.server.dao.util.mapping.JsonBinaryType; import javax.persistence.Column; import javax.persistence.Entity; @@ -44,7 +44,7 @@ import java.util.UUID; @Data @EqualsAndHashCode(callSuper = true) @Entity -@TypeDef(name = "json", typeClass = JsonStringType.class) +@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class) @Table(name = ModelConstants.DEVICE_PROFILE_COLUMN_FAMILY_NAME) public final class DeviceProfileEntity extends BaseSqlEntity implements SearchTextEntity { @@ -74,8 +74,8 @@ public final class DeviceProfileEntity extends BaseSqlEntity impl @Column(name = ModelConstants.DEVICE_PROFILE_DEFAULT_RULE_CHAIN_ID_PROPERTY, columnDefinition = "uuid") private UUID defaultRuleChainId; - @Type(type = "json") - @Column(name = ModelConstants.DEVICE_PROFILE_PROFILE_DATA_PROPERTY) + @Type(type = "jsonb") + @Column(name = ModelConstants.DEVICE_PROFILE_PROFILE_DATA_PROPERTY, columnDefinition = "jsonb") private JsonNode profileData; public DeviceProfileEntity() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java index ae5e6695e8..7c69f58935 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java @@ -28,6 +28,7 @@ import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.server.dao.util.mapping.JsonBinaryType; import org.thingsboard.server.dao.util.mapping.JsonStringType; import javax.persistence.Column; @@ -37,7 +38,7 @@ import javax.persistence.Table; @Data @EqualsAndHashCode(callSuper = true) @Entity -@TypeDef(name = "json", typeClass = JsonStringType.class) +@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class) @Table(name = ModelConstants.TENANT_PROFILE_COLUMN_FAMILY_NAME) public final class TenantProfileEntity extends BaseSqlEntity implements SearchTextEntity { @@ -59,8 +60,8 @@ public final class TenantProfileEntity extends BaseSqlEntity impl @Column(name = ModelConstants.TENANT_PROFILE_ISOLATED_TB_RULE_ENGINE) private boolean isolatedTbRuleEngine; - @Type(type = "json") - @Column(name = ModelConstants.TENANT_PROFILE_PROFILE_DATA_PROPERTY) + @Type(type = "jsonb") + @Column(name = ModelConstants.TENANT_PROFILE_PROFILE_DATA_PROPERTY, columnDefinition = "jsonb") private JsonNode profileData; public TenantProfileEntity() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JsonBinarySqlTypeDescriptor.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JsonBinarySqlTypeDescriptor.java new file mode 100644 index 0000000000..05d0315101 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JsonBinarySqlTypeDescriptor.java @@ -0,0 +1,52 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.util.mapping; + +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; +import java.sql.SQLException; +import java.sql.Types; + +public class JsonBinarySqlTypeDescriptor extends AbstractJsonSqlTypeDescriptor { + + public static final JsonBinarySqlTypeDescriptor INSTANCE = new JsonBinarySqlTypeDescriptor(); + + @Override + public int getSqlType() { + return Types.OTHER; + } + + @Override + public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicBinder(javaTypeDescriptor, this) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { + st.setObject(index, javaTypeDescriptor.unwrap(value, JsonNode.class, options), getSqlType()); + } + + @Override + protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) throws SQLException { + st.setObject(name, javaTypeDescriptor.unwrap(value, JsonNode.class, options), getSqlType()); + } + }; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JsonBinaryType.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JsonBinaryType.java new file mode 100644 index 0000000000..2eea7e7dc7 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JsonBinaryType.java @@ -0,0 +1,46 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.util.mapping; + +import org.hibernate.type.AbstractSingleColumnStandardBasicType; +import org.hibernate.usertype.DynamicParameterizedType; + +import java.util.Properties; + +public class JsonBinaryType extends AbstractSingleColumnStandardBasicType implements DynamicParameterizedType { + + public JsonBinaryType() { + super( + JsonBinarySqlTypeDescriptor.INSTANCE, + new JsonTypeDescriptor() + ); + } + + public String getName() { + return "jsonb"; + } + + @Override + protected boolean registerUnderJavaType() { + return true; + } + + @Override + public void setParameterValues(Properties parameters) { + ((JsonTypeDescriptor) getJavaTypeDescriptor()) + .setParameterValues(parameters); + } +} diff --git a/dao/src/main/resources/sql/schema-entities-hsql.sql b/dao/src/main/resources/sql/schema-entities-hsql.sql index 397352f4e1..4ca2d459e0 100644 --- a/dao/src/main/resources/sql/schema-entities-hsql.sql +++ b/dao/src/main/resources/sql/schema-entities-hsql.sql @@ -14,7 +14,6 @@ -- limitations under the License. -- - CREATE TABLE IF NOT EXISTS admin_settings ( id uuid NOT NULL CONSTRAINT admin_settings_pkey PRIMARY KEY, created_time bigint NOT NULL, @@ -129,7 +128,7 @@ CREATE TABLE IF NOT EXISTS device_profile ( name varchar(255), type varchar(255), transport_type varchar(255), - profile_data varchar, + profile_data jsonb, description varchar, search_text varchar(255), is_default boolean, @@ -144,7 +143,7 @@ CREATE TABLE IF NOT EXISTS device ( additional_info varchar, customer_id uuid, device_profile_id uuid NOT NULL, - device_data varchar, + device_data jsonb, type varchar(255), name varchar(255), label varchar(255), @@ -206,7 +205,7 @@ CREATE TABLE IF NOT EXISTS tenant_profile ( id uuid NOT NULL CONSTRAINT tenant_profile_pkey PRIMARY KEY, created_time bigint NOT NULL, name varchar(255), - profile_data varchar, + profile_data jsonb, description varchar, search_text varchar(255), is_default boolean, diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 8cba33aa7e..c797559df2 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -145,7 +145,7 @@ CREATE TABLE IF NOT EXISTS device_profile ( name varchar(255), type varchar(255), transport_type varchar(255), - profile_data varchar, + profile_data jsonb, description varchar, search_text varchar(255), is_default boolean, @@ -160,7 +160,7 @@ CREATE TABLE IF NOT EXISTS device ( additional_info varchar, customer_id uuid, device_profile_id uuid NOT NULL, - device_data varchar, + device_data jsonb, type varchar(255), name varchar(255), label varchar(255), @@ -229,7 +229,7 @@ CREATE TABLE IF NOT EXISTS tenant_profile ( id uuid NOT NULL CONSTRAINT tenant_profile_pkey PRIMARY KEY, created_time bigint NOT NULL, name varchar(255), - profile_data varchar, + profile_data jsonb, description varchar, search_text varchar(255), is_default boolean, diff --git a/dao/src/main/resources/sql/schema-types-hsql.sql b/dao/src/main/resources/sql/schema-types-hsql.sql new file mode 100644 index 0000000000..cadd830534 --- /dev/null +++ b/dao/src/main/resources/sql/schema-types-hsql.sql @@ -0,0 +1,20 @@ +-- +-- Copyright © 2016-2020 The Thingsboard Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +DROP TYPE json IF EXISTS; +CREATE TYPE json AS text; +DROP TYPE jsonb IF EXISTS; +CREATE TYPE jsonb AS other; diff --git a/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java b/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java index a6ef3935b0..06f1e70a20 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java +++ b/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java @@ -30,7 +30,7 @@ public class SqlDaoServiceTestSuite { @ClassRule public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/schema-entities-idx.sql" + Arrays.asList("sql/schema-types-hsql.sql", "sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/schema-entities-idx.sql" , "sql/system-data.sql" , "sql/system-test.sql" ), diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java index 561dfaf513..86099ef169 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java @@ -151,7 +151,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { public void testSaveSameDeviceProfileWithDifferentType() { DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"); DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); - //TODO: once we have mode profile types, we should test that we can not change profile type in runtime and uncomment the @Ignore. + //TODO: once we have more profile types, we should test that we can not change profile type in runtime and uncomment the @Ignore. // savedDeviceProfile.setType(DeviceProfileType.LWM2M); deviceProfileService.saveDeviceProfile(savedDeviceProfile); }