当前位置:  开发笔记 > 编程语言 > 正文

将java.lang.String类型映射为Postgres JSON类型

如何解决《将java.lang.String类型映射为PostgresJSON类型》经验,为你挑选了1个好方法。

我的问题与以下问题相关:将postgreSQL JSON列映射到Hibernate值类型,尽管当我测试在postgres中将字符串传递给psql时答案有效,但从Java代码传递字符串时却无法解决问题。

我正在使用MyBatis通过Spring注入将sql映射到postgres数据库。

这是MyBatis的Java接口,映射到Postgres JSON列时遇到问题的方法是updateState()方法。

package receiver.spoke;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import receiver.bean.Spoke;

public interface SpokeDAOMyBatis extends SpokeDAO {

    void updateState(@Param("id") long spokeId, @Param("state") String state);

    String getState(@Param("id") long spokeId);

    List getSpokes();

    // The close() method must exist.
    void close();

}

以下是我的映射器类:







    
        UPDATE 
            spokes 
        SET 
            state = #{state} 
        WHERE 
            id = #{id}
    

    

    

    
            
            
            
            
    


以下是Spoke bean类:

package receiver.bean;

import java.sql.Timestamp;

public class Spoke {

    private long id;
    private String description;
    private String uri;
    private Timestamp updatets;
//    private String state;

    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getDescription() {
        return this.description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getUri() {
        return this.uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    public Timestamp getUpdatets() {
        return updatets;
    }

    public void setUpdatets(Timestamp updatets) {
        this.updatets = updatets;
    }

//  public String getState() {
//      return (String) state;
//  }

//  public void setState(String state) {
//      this.state = state;
//  }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((this.description == null) ? 0 : this.description.hashCode());
        result = prime * result + (int) (this.id ^ (this.id >>> 32));
        result = prime * result + ((this.uri == null) ? 0 : this.uri.hashCode());
        result = prime * result + ((this.updatets == null) ? 0 : this.updatets.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Spoke other = (Spoke) obj;
        if (this.description == null) {
            if (other.description != null)
                return false;
        } else if (!this.description.equals(other.description))
            return false;
        if (this.id != other.id)
            return false;
        if (this.uri == null) {
            if (other.uri != null)
                return false;
        } else if (!this.uri.equals(other.uri))
            return false;
        if (this.updatets == null) {
            if (other.updatets != null)
                return false;
        } else if (!this.updatets.equals(other.updatets))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "SpokeData [id=" + this.id + ", description=" + this.description + ", uri=" + this.uri + "]";
    }

}

以下是我的applicationContext.xml文件的代码




    
        
            
                classpath:db.properties
            
        
    

    
        
        
        
        
    

    
        
        
    

    
        
        
    


以下是db.properties文件

test.db.url=jdbc:postgresql://localhost:5432/lunar
test.db.username=lunar
test.db.password=lunar

以下是mybatis-config.xml文件






    
        
        
        
        
        
    

这是包含json字段的辐条表

CREATE TABLE spokes (
    id BIGSERIAL NOT NULL,
    insertts TIMESTAMPTZ NOT NULL,
    updatets TIMESTAMPTZ NOT NULL,
    rowversion BIGINT NOT NULL,
    description TEXT NOT NULL,
    uri TEXT NOT NULL,
    state JSON
);

-- create primary key
ALTER TABLE spokes ADD CONSTRAINT pk_spokes PRIMARY KEY (id);

-- triggers
CREATE TRIGGER b_spokes_audit BEFORE INSERT OR UPDATE ON spokes FOR EACH ROW EXECUTE PROCEDURE trigger_function_aud$

-- grants
GRANT ALL ON TABLE spokes TO lunar;

下一步创建用于字符串到json转换的函数

CREATE OR REPLACE FUNCTION json_intext(text) RETURNS json AS $$
SELECT json_in($1::cstring); 
$$ LANGUAGE SQL IMMUTABLE;
CREATE FUNCTION

建立演员表

CREATE CAST (text AS json) WITH FUNCTION json_intext(text) AS IMPLICIT;
CREATE CAST

从我的psql而不是从Java端进行转换时,此方法有效

以下是一些测试,展示了该功能以及通过psql对名为xxx的表进行强制转换以及不接受无效json的事实

PREPARE test(text) AS INSERT INTO xxx(id,state) VALUES (1,$1);
PREPARE
execute test('{}');
INSERT 0 1
select json_in('a');
ERROR:  invalid input syntax for type json
DETAIL:  Token "a" is invalid.
CONTEXT:  JSON data, line 1: a
select json_in('a'::cstring);
ERROR:  invalid input syntax for type json
DETAIL:  Token "a" is invalid.
CONTEXT:  JSON data, line 1: a
select json_in('{}');
 json_in 
---------
 {}
(1 row)

select json_in('{');
ERROR:  invalid input syntax for type json
DETAIL:  The input string ended unexpectedly.
CONTEXT:  JSON data, line 1: {
select json_in('{}');
 json_in 
 ---------
  {}
(1 row)

以下是我的测试课:

package receiver.spoke;

import static org.junit.Assert.*;

import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbcp.BasicDataSource;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import receiver.bean.Spoke;
import receiver.spoke.SpokeDAOMyBatis;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/applicationContext.xml" })
public class SpokeDAOMyBatisTest {

    @Autowired 
    @Qualifier("spokeDAOMyBatis")
    private SpokeDAOMyBatis spokeDAOMyBatis;

    @Autowired
    @Qualifier("dataSource")
    private BasicDataSource datasource;

    @Before
    public void connectionTest() throws SQLException {     
        datasource.getConnection();
    }

    @Test
    public void updateState() {

        assertNotNull(spokeDAOMyBatis);
        spokeDAOMyBatis.updateState(1L, "{}");
        assertTrue("Returned wrong state", spokeDAOMyBatis.getState(1L).equals("{}"));
    }

    @Test
    public void getState() {

        assertNotNull(spokeDAOMyBatis);
        String str1 = spokeDAOMyBatis.getState(1L);
        String str2 = spokeDAOMyBatis.getState(2L);
        assertTrue("Returned wrong state", spokeDAOMyBatis.getState(1L).equals(str1));
        assertTrue("Returned wrong state", spokeDAOMyBatis.getState(2L).equals(str2));
    }

    @Test
    public void getAllSpokesTest() {

        assertNotNull(spokeDAOMyBatis);
        List list = spokeDAOMyBatis.getSpokes();
        System.out.println(list.toString());

        assertNotNull("List of spokes returned null", list);
        assertTrue("List of spokes is empty", !list.isEmpty());
        assertNotNull("Invalid spoke", list.get(0));
        assertNotNull("id not loaded", list.get(0).getId());
        assertNotNull("description not loaded", list.get(0).getDescription());
        assertNotNull("uri not loaded", list.get(0).getUri());
        assertNotNull("updatets not loaded", list.get(0).getUpdatets());
    }    
}

这样看来一切正常,但是当我尝试运行Java端时,我得到了强制转换异常,如下面的堆栈跟踪所示:

Tests run: 3, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.241 sec <<< FAILURE!
updateState(receiver.spoke.SpokeDAOMyBatisTest)  Time elapsed: 0.035 sec  <<< ERROR!
org.springframework.jdbc.BadSqlGrammarException: 
### Error updating database.  Cause: org.postgresql.util.PSQLException: ERROR: column "state" is of type json but expression is of type character varying
  Hint: You will need to rewrite or cast the expression.
  Position: 38
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: UPDATE     spokes    SET     state = ?    WHERE     id = ?
### Cause: org.postgresql.util.PSQLException: ERROR: column "state" is of type json but expression is of type character varying
  Hint: You will need to rewrite or cast the expression.
  Position: 38
; bad SQL grammar []; nested exception is org.postgresql.util.PSQLException: ERROR: column "state" is of type json but expression is of type character varying
  Hint: You will need to rewrite or cast the expression.
  Position: 38
    at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:231)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:74)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:399)
    at com.sun.proxy.$Proxy17.update(Unknown Source)
    at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:269)
    at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:55)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:53)
    at com.sun.proxy.$Proxy24.updateState(Unknown Source)
    at receiver.spoke.SpokeDAOMyBatisTest.updateState(SpokeDAOMyBatisTest.java:41)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: org.postgresql.util.PSQLException: ERROR: column "state" is of type json but expression is of type character varying
  Hint: You will need to rewrite or cast the expression.
  Position: 38
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2270)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1998)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:570)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:420)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:413)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:169)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:59)
    at com.sun.proxy.$Proxy23.execute(Unknown Source)
    at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:45)
    at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:73)
    at org.apache.ibatis.executor.ReuseExecutor.doUpdate(ReuseExecutor.java:51)
    at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:115)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:170)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:386)
    ... 42 more

3601 [Thread-0] INFO  org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@4fcd19b3: startup date [Mon Jan 11 11:10:54 GMT 2016]; root of context hierarchy

charlie f.. 5

建议以/sf/ask/17360801/将stringtype = unspecified添加到我的jdbc连接字符串中,建议可行:

jdbc:postgresql://localhost:5432/dbname?stringtype=unspecified

这样做,我还可以删除该函数并将其从字符串转换为json。

我还通过将无效的json传递给JSON列来测试了更改。

正如我希望的那样,我得到了一个DataIntegrityViolationException,正如我从测试中所期望的那样



1> charlie f..:

建议以/sf/ask/17360801/将stringtype = unspecified添加到我的jdbc连接字符串中,建议可行:

jdbc:postgresql://localhost:5432/dbname?stringtype=unspecified

这样做,我还可以删除该函数并将其从字符串转换为json。

我还通过将无效的json传递给JSON列来测试了更改。

正如我希望的那样,我得到了一个DataIntegrityViolationException,正如我从测试中所期望的那样

推荐阅读
手机用户2502851955
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有