Saltar al contenido

¿Cómo usar el tipo de datos Postgres JSONB con JPA?

Te doy la bienvenida a nuestro espacio, ahora vas a encontrar la solucíon de lo que buscabas.

Solución:

Todas las respuestas me ayudaron a llegar a la solución final que está lista para JPA y no específicamente para EclipseLink o Hibernate.

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import javax.json.Json;
import javax.json.JsonObject;
import javax.persistence.Converter;
import org.postgresql.util.PGobject;

@Converter(autoApply = true)
public class JsonConverter implements javax.persistence.AttributeConverter 

  private static final long serialVersionUID = 1L;
  private static ObjectMapper mapper = new ObjectMapper();

  @Override
  public Object convertToDatabaseColumn(JsonObject objectValue) 
    try 
      PGobject out = new PGobject();
      out.setType("json");
      out.setValue(objectValue.toString());
      return out;
     catch (Exception e) 
      throw new IllegalArgumentException("Unable to serialize to json field ", e);
    
  

  @Override
  public JsonObject convertToEntityAttribute(Object dataValue) 
    try 
      if (dataValue instanceof PGobject && ((PGobject) dataValue).getType().equals("json")) 
        return mapper.reader(new TypeReference() 
        ).readValue(((PGobject) dataValue).getValue());
      
      return Json.createObjectBuilder().build();
     catch (IOException e) 
      throw new IllegalArgumentException("Unable to deserialize to json field ", e);
    
  

Editar: ahora veo que esto es bastante Hibernate dependiente. Pero tal vez puedas encontrar algo similar para EclipseLink.

Solo agregaré lo que tengo como respuesta, se origina en otra respuesta SO, pero lo que sea. Esto mapeará jsonb para JsonObject de Google gson, pero puede cambiarlo por otro si es necesario. Para cambiar a otra cosa, cambia nullSafeGet, nullSafeSety deepCopy métodos.

public class JsonbType implements UserType 

    @Override
    public int[] sqlTypes() 
        return new int[]  Types.JAVA_OBJECT ;
    

    @Override
    public Class returnedClass() 
        return JsonObject.class;
    

    @Override
    public boolean equals(final Object x, final Object y)  y == null) 
            return false;
        
        return x.equals(y);
    

    @Override
    public int hashCode(final Object x) 
        if (x == null) 
            return 0;
        

        return x.hashCode();
    

    @Nullable
    @Override
    public Object nullSafeGet(final ResultSet rs,
                              final String[] names,
                              final SessionImplementor session,
                              final Object owner) throws SQLException 
        final String json = rs.getString(names[0]);
        if (json == null) 
            return null;
        

        final JsonParser jsonParser = new JsonParser();
        return jsonParser.parse(json).getAsJsonObject();
    

    @Override
    public void nullSafeSet(final PreparedStatement st,
                            final Object value,
                            final int index,
                            final SessionImplementor session) throws SQLException 
        if (value == null) 
            st.setNull(index, Types.OTHER);
            return;
        

        st.setObject(index, value.toString(), Types.OTHER);
    

    @Nullable
    @Override
    public Object deepCopy(@Nullable final Object value) 
        if (value == null) 
            return null;
        
        final JsonParser jsonParser = new JsonParser();
        return jsonParser.parse(value.toString()).getAsJsonObject();
    

    @Override
    public boolean isMutable() 
        return true;
    

    @Override
    public Serializable disassemble(final Object value) 
        final Object deepCopy = deepCopy(value);

        if (!(deepCopy instanceof Serializable)) 
            throw new SerializationException(
                    String.format("deepCopy of %s is not serializable", value), null);
        

        return (Serializable) deepCopy;
    

    @Nullable
    @Override
    public Object assemble(final Serializable cached, final Object owner) 
        return deepCopy(cached);
    

    @Nullable
    @Override
    public Object replace(final Object original, final Object target, final Object owner) 
        return deepCopy(original);
    

Para usar esto, haz lo siguiente:

public class SomeEntity {

    @Column(name = "jsonobject")
    @Type(type = "com.myapp.JsonbType") 
    private JsonObject jsonObject;

Además, debe configurar su dialecto para indicar que JAVA_OBJECT = jsonb:

registerColumnType(Types.JAVA_OBJECT, "jsonb");

Creo que encontré una analogía con UserType de Hibernate para EclipseLink.

http://www.eclipse.org/eclipselink/documentation/2.6/jpa/extensions/annotations_ref.htm#CHDEHJEB

Tienes que hacer una clase que implemente org.eclipse.persistence.mappings.converters.Converter y realiza la conversión por usted, luego use el @Convert anotación en cada campo en el que esté utilizando ese tipo.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *