Reducing boilerplate code for JSON mapping UserTypes

Jens Pelzetter 2020-05-23 16:30:01 +02:00
parent e5d0e5f329
commit 1f970809b3
2 changed files with 281 additions and 106 deletions

View File

@ -0,0 +1,163 @@
/*
* Copyright (C) 2020 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package org.libreccm.hibernate;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.UserType;
import org.libreccm.l10n.LocalizedString;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Objects;
import javax.json.Json;
import javax.json.JsonReader;
import javax.json.JsonWriter;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public abstract class AbstractCcmJsonUserType implements UserType {
@Override
public int[] sqlTypes() {
return new int[]{Types.JAVA_OBJECT};
}
@Override
public Class<LocalizedString> returnedClass() {
return LocalizedString.class;
}
@Override
public boolean equals(final Object obj1, final Object obj2)
throws HibernateException {
return Objects.equals(obj1, obj2);
}
@Override
public int hashCode(final Object obj) throws HibernateException {
return Objects.hashCode(obj);
}
@Override
public Object nullSafeGet(
final ResultSet resultSet,
final String[] names,
final SharedSessionContractImplementor session,
final Object owner
) throws HibernateException, SQLException {
final String cellContent = resultSet.getString(names[0]);
if (cellContent == null) {
return null;
} else {
try (StringReader strReader = new StringReader(cellContent);
JsonReader jsonReader = Json.createReader(strReader)) {
return nullSafeGet(jsonReader);
}
}
}
protected abstract Object nullSafeGet(final JsonReader jsonReader);
@Override
public void nullSafeSet(
final PreparedStatement statement,
final Object value,
final int index,
final SharedSessionContractImplementor session
) throws HibernateException, SQLException {
if (value == null) {
statement.setObject(index, null, Types.OTHER);
} else {
try (StringWriter strWriter = new StringWriter();
JsonWriter jsonWriter = Json.createWriter(strWriter)) {
nullSafeSet(value, jsonWriter);
statement.setObject(index, strWriter.toString(), Types.OTHER);
}catch (IOException ex) {
throw new HibernateException(ex);
}
}
}
protected abstract void nullSafeSet(
final Object value, final JsonWriter jsonWriter
);
@Override
public Object deepCopy(final Object value) throws HibernateException {
final byte[] serialized;
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(value);
oos.flush();
serialized = bos.toByteArray();
} catch (IOException ex) {
throw new HibernateException(ex);
}
final Object obj;
try (ByteArrayInputStream bais = new ByteArrayInputStream(serialized);
ObjectInputStream ois = new ObjectInputStream(bais)) {
obj = ois.readObject();
} catch (IOException | ClassNotFoundException ex) {
throw new HibernateException(ex);
}
return obj;
}
@Override
public boolean isMutable() {
return true;
}
@Override
public Serializable disassemble(final Object value)
throws HibernateException {
return (Serializable) deepCopy(value);
}
@Override
public Object assemble(final Serializable cached, final Object owner) throws
HibernateException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Object replace(
final Object original,
final Object target,
final Object owner
) throws HibernateException {
return deepCopy(original);
}
}

View File

@ -21,6 +21,7 @@ package org.libreccm.l10n;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.UserType;
import org.libreccm.hibernate.AbstractCcmJsonUserType;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@ -42,120 +43,131 @@ import javax.json.JsonReader;
import javax.json.JsonWriter;
/**
* Hibernate User type mapping instances of {@link LocalizedString} to a JSON.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class LocalizedStringType implements UserType {
public class LocalizedStringType extends AbstractCcmJsonUserType {
@Override
public int[] sqlTypes() {
return new int[]{Types.JAVA_OBJECT};
protected Object nullSafeGet(final JsonReader jsonReader) {
return LocalizedString.fromJson(jsonReader.readObject());
}
@Override
public Class<LocalizedString> returnedClass() {
return LocalizedString.class;
protected void nullSafeSet(
final Object value, final JsonWriter jsonWriter
) {
jsonWriter.writeObject(((LocalizedString) value).toJson());
}
//implements UserType {
@Override
public boolean equals(final Object obj1, final Object obj2)
throws HibernateException {
return Objects.equals(obj1, obj2);
}
@Override
public int hashCode(final Object obj) throws HibernateException {
return Objects.hashCode(obj);
}
@Override
public Object nullSafeGet(
final ResultSet resultSet,
final String[] names,
final SharedSessionContractImplementor session,
final Object owner
) throws HibernateException, SQLException {
final String cellContent = resultSet.getString(names[0]);
if (cellContent == null) {
return null;
} else {
try (StringReader strReader = new StringReader(cellContent);
JsonReader jsonReader = Json.createReader(strReader)) {
return LocalizedString.fromJson(jsonReader.readObject());
}
}
}
@Override
public void nullSafeSet(
final PreparedStatement statement,
final Object value,
final int index,
final SharedSessionContractImplementor session
) throws HibernateException, SQLException {
if (value == null) {
statement.setObject(index, null, Types.OTHER);
} else {
final JsonObject jsonObject = ((LocalizedString) value).toJson();
try (StringWriter strWriter = new StringWriter();
JsonWriter jsonWriter = Json.createWriter(strWriter)) {
jsonWriter.writeObject(jsonObject);
statement.setObject(index, strWriter.toString(), Types.OTHER);
} catch (IOException ex) {
throw new HibernateException(ex);
}
}
}
@Override
public Object deepCopy(final Object value) throws HibernateException {
final byte[] serialized;
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(value);
oos.flush();
serialized = bos.toByteArray();
} catch (IOException ex) {
throw new HibernateException(ex);
}
final Object obj;
try (final ByteArrayInputStream bais = new ByteArrayInputStream(
serialized
);
final ObjectInputStream ois = new ObjectInputStream(bais);) {
obj = ois.readObject();
} catch (IOException | ClassNotFoundException ex) {
throw new HibernateException(ex);
}
return obj;
}
@Override
public boolean isMutable() {
return true;
}
@Override
public Serializable disassemble(final Object value)
throws HibernateException {
return (Serializable) deepCopy(value);
}
@Override
public Object assemble(final Serializable cached, final Object owner) throws
HibernateException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Object replace(
final Object original,
final Object target,
final Object owner
) throws HibernateException {
return deepCopy(original);
}
// @Override
// public int[] sqlTypes() {
// return new int[]{Types.JAVA_OBJECT};
// }
//
// @Override
// public Class<LocalizedString> returnedClass() {
// return LocalizedString.class;
// }
//
// @Override
// public boolean equals(final Object obj1, final Object obj2)
// throws HibernateException {
// return Objects.equals(obj1, obj2);
// }
//
// @Override
// public int hashCode(final Object obj) throws HibernateException {
// return Objects.hashCode(obj);
// }
//
// @Override
// public Object nullSafeGet(
// final ResultSet resultSet,
// final String[] names,
// final SharedSessionContractImplementor session,
// final Object owner
// ) throws HibernateException, SQLException {
// final String cellContent = resultSet.getString(names[0]);
// if (cellContent == null) {
// return null;
// } else {
// try (StringReader strReader = new StringReader(cellContent);
// JsonReader jsonReader = Json.createReader(strReader)) {
// return LocalizedString.fromJson(jsonReader.readObject());
// }
// }
// }
//
// @Override
// public void nullSafeSet(
// final PreparedStatement statement,
// final Object value,
// final int index,
// final SharedSessionContractImplementor session
// ) throws HibernateException, SQLException {
// if (value == null) {
// statement.setObject(index, null, Types.OTHER);
// } else {
// final JsonObject jsonObject = ((LocalizedString) value).toJson();
// try (StringWriter strWriter = new StringWriter();
// JsonWriter jsonWriter = Json.createWriter(strWriter)) {
// jsonWriter.writeObject(jsonObject);
// statement.setObject(index, strWriter.toString(), Types.OTHER);
// } catch (IOException ex) {
// throw new HibernateException(ex);
// }
// }
// }
//
// @Override
// public Object deepCopy(final Object value) throws HibernateException {
// final byte[] serialized;
// try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
// ObjectOutputStream oos = new ObjectOutputStream(bos)) {
// oos.writeObject(value);
// oos.flush();
// serialized = bos.toByteArray();
// } catch (IOException ex) {
// throw new HibernateException(ex);
// }
//
// final Object obj;
// try (ByteArrayInputStream bais = new ByteArrayInputStream(serialized);
// ObjectInputStream ois = new ObjectInputStream(bais)) {
// obj = ois.readObject();
// } catch (IOException | ClassNotFoundException ex) {
// throw new HibernateException(ex);
// }
// return obj;
// }
//
// @Override
// public boolean isMutable() {
// return true;
// }
//
// @Override
// public Serializable disassemble(final Object value)
// throws HibernateException {
// return (Serializable) deepCopy(value);
// }
//
// @Override
// public Object assemble(final Serializable cached, final Object owner) throws
// HibernateException {
// throw new UnsupportedOperationException("Not supported yet.");
// }
//
// @Override
// public Object replace(
// final Object original,
// final Object target,
// final Object owner
// ) throws HibernateException {
// return deepCopy(original);
// }
}