Skip to content

Commit

Permalink
Merge branch 'example6'
Browse files Browse the repository at this point in the history
  • Loading branch information
kuthanm committed Jan 3, 2014
2 parents f6cde78 + 859d62f commit 155f85b
Show file tree
Hide file tree
Showing 14 changed files with 355 additions and 3 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@ Example 5

Aggregate entity with simple audit.

Example 6
---------

Custom type for CLOB (e.g: JSON).
4 changes: 2 additions & 2 deletions src/main/java/design/domain/example5/audit/Audit.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ public class Audit extends AbstractValueObject {
@AttributeOverride(name = AuditIdentity.DETAILS_PROPERTY_NAME, column = @Column(name = "audit_modifier_details", nullable = false)) })
private AuditIdentity modifier;

protected Audit() {
Audit() {
}

protected Audit(Date creationDate, AuditIdentity creator, Date modificationDate, AuditIdentity modifier) {
Audit(Date creationDate, AuditIdentity creator, Date modificationDate, AuditIdentity modifier) {
this.creationDate = requireNonNull(creationDate);
this.creator = requireNonNull(creator);
this.modificationDate = requireNonNull(modificationDate);
Expand Down
46 changes: 46 additions & 0 deletions src/main/java/design/domain/example6/Example6.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package design.domain.example6;

import static java.util.Objects.requireNonNull;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;

import org.hibernate.annotations.Columns;

import design.domain.example6.clob.ClobHolder;

@Entity
public class Example6 {

@Id
private String id;

@Version
private Integer version;

@Columns(columns = { @Column(name = "value_object_json_class"), @Column(name = "value_object_json_value") })
private ClobHolder<Example6Clob> clobHolder = ClobHolder.absent();

Example6() {
}

public Example6(String id, Example6Clob valueObject) {
this.id = requireNonNull(id);
this.clobHolder = ClobHolder.of(valueObject);
}

public String getId() {
return id;
}

public Integer getVersion() {
return version;
}

public Example6Clob getValueObject() {
return clobHolder.getValue();
}

}
27 changes: 27 additions & 0 deletions src/main/java/design/domain/example6/Example6Clob.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package design.domain.example6;

import static java.util.Objects.requireNonNull;

import javax.persistence.Embeddable;

import ddd.domain.AbstractValueObject;

@Embeddable
public class Example6Clob extends AbstractValueObject {

private static final long serialVersionUID = 1L;

private String name;

Example6Clob() {
}

public Example6Clob(String name) {
this.name = requireNonNull(name);
}

public String getName() {
return name;
}

}
6 changes: 6 additions & 0 deletions src/main/java/design/domain/example6/Example6Repository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package design.domain.example6;

import ddd.domain.Repository;

public interface Example6Repository extends Repository<Example6, String> {
}
34 changes: 34 additions & 0 deletions src/main/java/design/domain/example6/clob/ClobHolder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package design.domain.example6.clob;

import static java.util.Objects.requireNonNull;

import java.io.Serializable;

public class ClobHolder<T> implements Serializable {

private static final long serialVersionUID = 1L;

private T value;

ClobHolder() {
}

public static <T> ClobHolder<T> of(T value) {
ClobHolder<T> jsonHolder = new ClobHolder<T>();
jsonHolder.value = requireNonNull(value);
return jsonHolder;
}

public static <T> ClobHolder<T> absent() {
return new ClobHolder<T>();
}

public T getValue() {
return value;
}

public boolean hasValue() {
return value != null;
}

}
9 changes: 9 additions & 0 deletions src/main/java/design/domain/example6/clob/ClobSerializer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package design.domain.example6.clob;

public interface ClobSerializer {

String toClob(Object object);

Object fromClob(String clob, String type);

}
2 changes: 1 addition & 1 deletion src/main/java/design/infrastructure/jpa/JpaConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();

entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPackagesToScan("design.domain");
entityManagerFactoryBean.setPackagesToScan("design");
entityManagerFactoryBean.setMappingResources("orm.xml");
entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter);
entityManagerFactoryBean.setJpaPropertyMap(jpaProperties);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package design.infrastructure.jpa.repositories;

import org.springframework.stereotype.Component;

import ddd.infrastructure.jpa.AbstractJpaRepository;
import design.domain.example6.Example6;
import design.domain.example6.Example6Repository;

@Component
public class JpaExample6Repository extends AbstractJpaRepository<Example6, String> implements Example6Repository {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package design.infrastructure.jpa.types;

import java.io.Serializable;
import java.util.Objects;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;

public abstract class AbstractCustomType {

public void setPropertyValue(Object component, int propertyIndex, Object value) throws HibernateException {
throw new HibernateException("Called setPropertyValue on an immutable type {" + component.getClass() + "}");
}

public boolean equals(Object x, Object y) throws HibernateException {
return Objects.equals(x, y);
}

public int hashCode(Object x) throws HibernateException {
return Objects.hashCode(x);
}

public Object deepCopy(Object value) throws HibernateException {
return value;
}

public boolean isMutable() {
return false;
}

public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}

public Serializable disassemble(Object value, SessionImplementor session) throws HibernateException {
return (Serializable) value;
}

public Object assemble(Serializable cached, SessionImplementor session, Object owner) throws HibernateException {
return cached;
}

public Object assemble(Serializable cached, Object value) throws HibernateException {
return cached;
}

public Object replace(Object original, Object target, SessionImplementor session, Object owner)
throws HibernateException {
return original;
}

public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}

}
97 changes: 97 additions & 0 deletions src/main/java/design/infrastructure/jpa/types/ClobHolderType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package design.infrastructure.jpa.types;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.StringType;
import org.hibernate.type.TextType;
import org.hibernate.type.Type;
import org.hibernate.usertype.CompositeUserType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import design.domain.example6.clob.ClobHolder;
import design.domain.example6.clob.ClobSerializer;

@Component
public class ClobHolderType extends AbstractCustomType implements CompositeUserType {

private static ClobSerializer clobSerializer;

@Autowired
void setJsonSerializationService(ClobSerializer clobSerializer) {
ClobHolderType.clobSerializer = clobSerializer;
}

@Override
public String[] getPropertyNames() {
return new String[] { "type", "data" };
}

@Override
public Type[] getPropertyTypes() {
return new Type[] { StringType.INSTANCE, TextType.INSTANCE };
}

@SuppressWarnings("rawtypes")
@Override
public Class<ClobHolder> returnedClass() {
return ClobHolder.class;
}

@SuppressWarnings("rawtypes")
@Override
public Object getPropertyValue(Object component, int propertyIndex) throws HibernateException {
if (component == null) {
return null;
}

ClobHolder clobHolder = (ClobHolder) component;
if (!clobHolder.hasValue()) {
return null;
}

switch (propertyIndex) {
case 0:
return clobHolder.getValue().getClass().getName();
case 1:
return clobSerializer.toClob(clobHolder.getValue());
default:
throw new HibernateException("Invalid property index [" + propertyIndex + "]");
}
}

@Override
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {

String type = StringType.INSTANCE.nullSafeGet(rs, names[0], session);
String data = TextType.INSTANCE.nullSafeGet(rs, names[1], session);

if (type == null && data == null) {
return null;
} else {
Object json = clobSerializer.fromClob(data, type);
return ClobHolder.of(json);
}
}

@SuppressWarnings("rawtypes")
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
ClobHolder clobHolder = (ClobHolder) value;

if (clobHolder != null && clobHolder.getValue() != null) {
StringType.INSTANCE.set(st, clobHolder.getValue().getClass().getName(), index, session);
TextType.INSTANCE.set(st, clobSerializer.toClob(clobHolder.getValue()), index + 1, session);
} else {
StringType.INSTANCE.set(st, null, index, session);
TextType.INSTANCE.set(st, null, index + 1, session);
}
}

}
13 changes: 13 additions & 0 deletions src/main/java/design/infrastructure/jpa/types/CustomTypes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package design.infrastructure.jpa.types;

import javax.persistence.MappedSuperclass;

import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;

import design.domain.example6.clob.ClobHolder;

@MappedSuperclass
@TypeDefs({ @TypeDef(defaultForType = ClobHolder.class, typeClass = ClobHolderType.class) })
public class CustomTypes {
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;

import design.domain.example5.audit.Auditor;
import design.domain.example6.clob.ClobSerializer;
import design.infrastructure.jpa.JpaConfig;

@ContextConfiguration(classes = JpaConfig.class)
Expand Down Expand Up @@ -42,6 +43,11 @@ public Auditor auditor() {
return Mockito.mock(Auditor.class);
}

@Bean
public ClobSerializer clobSerializer() {
return Mockito.mock(ClobSerializer.class);
}

}

}
Loading

0 comments on commit 155f85b

Please sign in to comment.