Closed quicklyfast closed 3 months ago
Add the getValue method in Type to deserialize JSON data from a ResultSet into an object of the specified class (clazz).
package com.example; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.querydsl.core.types.Path; import com.querydsl.sql.Configuration; import com.querydsl.sql.MySQLTemplates; import com.querydsl.sql.RelationalPathBase; import com.querydsl.sql.SQLTemplates; import com.querydsl.sql.mysql.MySQLQueryFactory; import com.querydsl.sql.types.Type; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.jdbc.datasource.DataSourceUtils; import javax.sql.DataSource; import java.io.IOException; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.util.Arrays; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; /** * ExampleTest class with QueryDSL configuration and JSON handling for DataSource properties. */ @SpringBootConfiguration @Import(ExampleTest.QueryDSLConfiguration.class) @SpringBootTest @EnableAutoConfiguration class ExampleTest { /** * Interface representing a JSON entity. */ interface JsonEntity { } /** * JSON type handler using ObjectMapper to convert JSON strings to specified type objects. */ static class JSONType implements Type<JsonEntity> { private final ObjectMapper objectMapper; public JSONType() { objectMapper = new ObjectMapper(); objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true); objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); } @Override public int[] getSQLTypes() { return new int[]{Types.BLOB, Types.VARBINARY, Types.VARCHAR, Types.BINARY}; } @Override public Class<JsonEntity> getReturnedClass() { return JsonEntity.class; } @Override public String getLiteral(JsonEntity value) { if (value == null) { return null; } try { return objectMapper.writeValueAsString(value); } catch (JsonProcessingException e) { throw new RuntimeException(e); } } @Override public JsonEntity getValue(ResultSet rs, int startIndex) throws SQLException { try { return objectMapper.readValue(rs.getBytes(startIndex), JsonEntity.class); } catch (IOException e) { throw new RuntimeException(e); } } @Override public JsonEntity getValue(ResultSet rs, int startIndex, Class<JsonEntity> clazz) throws SQLException { try { return objectMapper.readValue(rs.getBytes(startIndex), clazz); } catch (IOException e) { throw new RuntimeException(e); } } @Override public void setValue(PreparedStatement st, int startIndex, JsonEntity value) throws SQLException { st.setObject(startIndex, getLiteral(value)); } } /** * DataSourceProperties class representing the properties of a data source. */ public static class DataSourceProperties implements JsonEntity { private String hostname; private int port; private String schema; private String username; private String password; private Map<String, Object> connectionProperties; public String getHostname() { return hostname; } public void setHostname(String hostname) { this.hostname = hostname; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public String getSchema() { return schema; } public void setSchema(String schema) { this.schema = schema; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Map<String, Object> getConnectionProperties() { return connectionProperties; } public void setConnectionProperties(Map<String, Object> connectionProperties) { this.connectionProperties = connectionProperties; } } /** * DataSourceEntity class representing a data source entity. * * <pre> * CREATE TABLE `data_source` ( * `id` int NOT NULL AUTO_INCREMENT, * `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, * `properties` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL, * PRIMARY KEY (`id`) USING BTREE * ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; * * INSERT INTO `data_source` VALUES (1, 'mysql-localhost', '{\"hostname\": \"localhost\", \"port\": 3306, \"schema\": \"test\", \"username\": \"root\", \"password\": \"root\", \"connectionProperties\": {\"useSSL\": true, \"useCursorFetch\": true}}'); * </pre> */ public static class DataSourceEntity { private Integer id; private String name; private DataSourceProperties properties; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public DataSourceProperties getProperties() { return properties; } public void setProperties(DataSourceProperties properties) { this.properties = properties; } } /** * QDataSourceEntity class representing the QueryDSL path for the DataSourceEntity. */ public static class QDataSourceEntity extends RelationalPathBase<DataSourceEntity> { public QDataSourceEntity() { this(DataSourceEntity.class, "ds", null, "data_source"); } public QDataSourceEntity(Class<? extends DataSourceEntity> type, String variable, String schema, String table) { super(type, variable, schema, table); } @Override public List<Path<?>> getColumns() { return Arrays.asList( createNumber("id", Integer.class), createString("name"), createSimple("properties", DataSourceProperties.class) ); } } /** * QueryDSL configuration class. */ static class QueryDSLConfiguration { /** * SQLTemplates implementation for MySQL. */ @Bean public SQLTemplates sqlTemplates() { return new MySQLTemplates(); } /** * MySQLQueryFactory - main entry point to build and execute SQL queries. */ @Bean public MySQLQueryFactory queryFactory(DataSource dataSource) { Configuration configuration = new Configuration(new MySQLTemplates()); configuration.register(new JSONType()); return new MySQLQueryFactory(configuration, () -> DataSourceUtils.getConnection(dataSource)); } } @Autowired private MySQLQueryFactory queryFactory; @Test public void test() { QDataSourceEntity qDataSource = new QDataSourceEntity(); List<DataSourceEntity> list = queryFactory.selectFrom(qDataSource).fetch(); DataSourceEntity dataSourceEntity = list.get(0); assertEquals("localhost", dataSourceEntity.getProperties().getHostname()); } }
Hi @quicklyfast, I tried to incorporate some more of your example into querydsl code base
Please let me know what you think
Add the getValue method in Type to deserialize JSON data from a ResultSet into an object of the specified class (clazz).