将JSON对象映射到Hibernate实体

Fra*_*ste 7 java rest spring json hibernate

我将开始一个使用Spring管理的REST应用程序项目和我的模型的Hibernate项目.

我知道Spring允许您从HTTP请求中获取Java对象(带@Consumes(JSON)注释).如果这个Java对象也是一个Hibernate实体,有没有冲突?嵌套对象是否正常工作(如@ManyToOne关系)?

Vla*_*cea 7

正如我在本文中解释的那样,使用Hibernate持久化JSON对象非常容易.

您不必手动创建所有这些类型,只需使用以下依赖项通过Maven Central获取它们:

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>${hibernate-types.version}</version> 
</dependency> 
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请查看hibernate类型的开源项目.

我写了一篇关于如何在PostgreSQL和MySQL上映射JSON对象的文章.

对于PostgreSQL,您需要以二进制形式发送JSON对象:

public class JsonBinaryType
    extends AbstractSingleColumnStandardBasicType<Object> 
    implements DynamicParameterizedType {

    public JsonBinaryType() {
        super( 
            JsonBinarySqlTypeDescriptor.INSTANCE, 
            new JsonTypeDescriptor()
        );
    }

    public String getName() {
        return "jsonb";
    }

    @Override
    public void setParameterValues(Properties parameters) {
        ((JsonTypeDescriptor) getJavaTypeDescriptor())
            .setParameterValues(parameters);
    }

}
Run Code Online (Sandbox Code Playgroud)

JsonBinarySqlTypeDescriptor如下所示:

public class JsonBinarySqlTypeDescriptor
    extends AbstractJsonSqlTypeDescriptor {

    public static final JsonBinarySqlTypeDescriptor INSTANCE = 
        new JsonBinarySqlTypeDescriptor();

    @Override
    public <X> ValueBinder<X> getBinder(
        final JavaTypeDescriptor<X> javaTypeDescriptor) {
        return new BasicBinder<X>(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()
                );
            }
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

JsonTypeDescriptor类的:

public class JsonTypeDescriptor
        extends AbstractTypeDescriptor<Object> 
        implements DynamicParameterizedType {

    private Class<?> jsonObjectClass;

    @Override
    public void setParameterValues(Properties parameters) {
        jsonObjectClass = ( (ParameterType) parameters.get( PARAMETER_TYPE ) )
            .getReturnedClass();

    }

    public JsonTypeDescriptor() {
        super( Object.class, new MutableMutabilityPlan<Object>() {
            @Override
            protected Object deepCopyNotNull(Object value) {
                return JacksonUtil.clone(value);
            }
        });
    }

    @Override
    public boolean areEqual(Object one, Object another) {
        if ( one == another ) {
            return true;
        }
        if ( one == null || another == null ) {
            return false;
        }
        return JacksonUtil.toJsonNode(JacksonUtil.toString(one)).equals(
                JacksonUtil.toJsonNode(JacksonUtil.toString(another)));
    }

    @Override
    public String toString(Object value) {
        return JacksonUtil.toString(value);
    }

    @Override
    public Object fromString(String string) {
        return JacksonUtil.fromString(string, jsonObjectClass);
    }

    @SuppressWarnings({ "unchecked" })
    @Override
    public <X> X unwrap(Object value, Class<X> type, WrapperOptions options) {
        if ( value == null ) {
            return null;
        }
        if ( String.class.isAssignableFrom( type ) ) {
            return (X) toString(value);
        }
        if ( Object.class.isAssignableFrom( type ) ) {
            return (X) JacksonUtil.toJsonNode(toString(value));
        }
        throw unknownUnwrap( type );
    }

    @Override
    public <X> Object wrap(X value, WrapperOptions options) {
        if ( value == null ) {
            return null;
        }
        return fromString(value.toString());
    }

}
Run Code Online (Sandbox Code Playgroud)

现在,您需要在类级别或package-info.java包级别描述符中声明新类型:

@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
Run Code Online (Sandbox Code Playgroud)

实体映射将如下所示:

@Type(type = "jsonb")
@Column(columnDefinition = "json")
private Location location;
Run Code Online (Sandbox Code Playgroud)

而已!


oce*_*ize 3

我们使用这种方法来简化设计并摆脱许多 dto(我们滥用它们太多了)。基本上,它对我们有用。

然而,在我们的 REST 模型中,我们试图不公开对象的其他关系,因为您始终可以创建另一个 REST 资源来访问它们。

所以我们只需@JsonIgnore对关系映射添加注释,例如@OneToManyor@ManyToOne使它们短暂。

我发现的另一个问题是,如果您仍然想返回这些关系,则必须对Join.FETCH它们使用策略或将事务管理移至更高级别,以便当响应序列化为 JSON(在视图模式中打开会话)时事务仍然存在。我认为这两种解决方案都不是很好。