Skip to content

Commit

Permalink
PLANNER-444 Extract AbstractScoreHibernateType
Browse files Browse the repository at this point in the history
  • Loading branch information
ge0ffrey committed Sep 17, 2015
1 parent 42a320f commit 1080cbb
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 123 deletions.
@@ -0,0 +1,78 @@
/*
* Copyright 2015 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.optaplanner.persistence.jpa.impl.score;

import java.io.Serializable;

import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.CompositeUserType;

/**
* This class is Hibernate specific, because JPA 2.1's @Converter currently
* cannot handle 1 class mapping to multiple SQL columns.
*/
public abstract class AbstractScoreHibernateType implements CompositeUserType {

@Override
public boolean isMutable() {
return false;
}

@Override
public Object deepCopy(Object value) {
return value; // Score is immutable
}

@Override
public Object replace(Object original, Object target, SessionImplementor session, Object owner) {
return original; // Score is immutable
}

@Override
public void setPropertyValue(Object component, int property, Object value) {
throw new UnsupportedOperationException("A Score is immutable.");
}

@Override
public boolean equals(Object a, Object b) {
if (a == b) {
return true;
} else if (a == null || b == null) {
return false;
}
return a.equals(b);
}

@Override
public int hashCode(Object o) {
if (o == null) {
return 0;
}
return o.hashCode();
}

@Override
public Serializable disassemble(Object value, SessionImplementor session) {
return (Serializable) value;
}

@Override
public Object assemble(Serializable cached, SessionImplementor session, Object owner) {
return cached;
}

}
Expand Up @@ -28,61 +28,26 @@
import org.hibernate.usertype.CompositeUserType;
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
import org.optaplanner.core.impl.score.buildin.hardsoft.HardSoftScoreDefinition;
import org.optaplanner.persistence.jpa.impl.score.AbstractScoreHibernateType;

/**
* This class is Hibernate specific, because JPA 2.1's @Converter currently
* cannot handle 1 class mapping to multiple SQL columns.
* {@inheritDoc}
*/
public class HardSoftScoreHibernateType implements CompositeUserType {

protected HardSoftScoreDefinition scoreDefinition = new HardSoftScoreDefinition();

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

@Override
public Type[] getPropertyTypes() {
return new Type[] {IntegerType.INSTANCE, IntegerType.INSTANCE};
}
public class HardSoftScoreHibernateType extends AbstractScoreHibernateType {

@Override
public Class returnedClass() {
return HardSoftScore.class;
}

@Override
public boolean isMutable() {
return false;
}

@Override
public Object deepCopy(Object value) {
return value; // Score is immutable
}

@Override
public Object replace(Object original, Object target, SessionImplementor session, Object owner) {
return original; // Score is immutable
}

@Override
public boolean equals(Object a, Object b) {
if (a == b) {
return true;
} else if (a == null || b == null) {
return false;
}
return a.equals(b);
public String[] getPropertyNames() {
return new String[] {"hardScore", "softScore"};
}

@Override
public int hashCode(Object o) {
if (o == null) {
return 0;
}
return o.hashCode();
public Type[] getPropertyTypes() {
return new Type[] {IntegerType.INSTANCE, IntegerType.INSTANCE};
}

@Override
Expand All @@ -98,16 +63,10 @@ public Object getPropertyValue(Object o, int propertyIndex) {
return score.getSoftScore();
default:
throw new IllegalArgumentException("The propertyIndex (" + propertyIndex
+ ") must be lower than the levelsSize (" + scoreDefinition.getLevelsSize()
+ ") for score (" + score + ").");
+ ") must be lower than the levelsSize for score (" + score + ").");
}
}

@Override
public void setPropertyValue(Object component, int property, Object value) {
throw new UnsupportedOperationException("A Score is immutable.");
}

@Override
public HardSoftScore nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner)
throws SQLException {
Expand Down Expand Up @@ -135,14 +94,4 @@ public void nullSafeSet(PreparedStatement statement, Object value, int parameter
statement.setInt(parameterIndex + 1, score.getSoftScore());
}

@Override
public Serializable disassemble(Object value, SessionImplementor session) {
return (Serializable) value;
}

@Override
public Object assemble(Serializable cached, SessionImplementor session, Object owner) {
return cached;
}

}
@@ -0,0 +1,97 @@
/*
* Copyright 2015 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.optaplanner.persistence.jpa.impl.score;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Persistence;
import javax.persistence.Transient;

import org.junit.BeforeClass;
import org.optaplanner.core.api.score.Score;
import org.optaplanner.persistence.jpa.impl.score.buildin.hardsoft.HardSoftScoreHibernateTypeTest;

import static org.junit.Assert.*;

public abstract class AbstractScoreHibernateTypeTest {

protected static EntityManagerFactory entityManagerFactory;

@BeforeClass
public static void setup() {
entityManagerFactory = Persistence.createEntityManagerFactory("optaplanner-persistence-jpa-test");
}

protected <S extends Score, E extends AbstractTestJpaEntity<S>> Long persistAndAssert(E jpaEntity) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(jpaEntity);
transaction.commit();
Long id = jpaEntity.getId();
assertNotNull(id);
return id;
}

protected <S extends Score, E extends AbstractTestJpaEntity<S>> void findAssertAndChangeScore(
Class<E> jpaEntityClass, Long id, S oldScore, S newScore) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
E jpaEntity = entityManager.find(jpaEntityClass, id);
assertEquals(oldScore, jpaEntity.getScore());
jpaEntity.setScore(newScore);
jpaEntity = entityManager.merge(jpaEntity);
transaction.commit();
}

protected <S extends Score, E extends AbstractTestJpaEntity<S>> void findAndAssert(
Class<E> jpaEntityClass, Long id, S score) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
E jpaEntity = entityManager.find(jpaEntityClass, id);
assertEquals(score, jpaEntity.getScore());
transaction.commit();
}

@MappedSuperclass
protected static abstract class AbstractTestJpaEntity<S extends Score> {

protected Long id;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}

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

@Transient
public abstract S getScore();
public abstract void setScore(S score);

}
}
Expand Up @@ -37,14 +37,7 @@

import static org.junit.Assert.*;

public class HardSoftScoreHibernateTypeTest {

protected static EntityManagerFactory entityManagerFactory;

@BeforeClass
public static void setup() {
entityManagerFactory = Persistence.createEntityManagerFactory("optaplanner-persistence-jpa-test");
}
public class HardSoftScoreHibernateTypeTest extends org.optaplanner.persistence.jpa.impl.score.AbstractScoreHibernateTypeTest {

@Test
public void persistAndMerge() {
Expand All @@ -53,62 +46,8 @@ public void persistAndMerge() {
findAndAssert(TestJpaEntity.class, id, HardSoftScore.valueOf(-10, -2));
}

protected Long persistAndAssert(TestJpaEntity jpaEntity) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(jpaEntity);
transaction.commit();
Long id = jpaEntity.getId();
assertNotNull(id);
return id;
}

protected <S extends Score, E extends AbstractTestJpaEntity<S>> void findAssertAndChangeScore(
Class<E> jpaEntityClass, Long id, S oldScore, S newScore) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
E jpaEntity = entityManager.find(jpaEntityClass, id);
assertEquals(oldScore, jpaEntity.getScore());
jpaEntity.setScore(newScore);
jpaEntity = entityManager.merge(jpaEntity);
transaction.commit();
}

protected <S extends Score, E extends AbstractTestJpaEntity<S>> void findAndAssert(
Class<E> jpaEntityClass, Long id, S score) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
E jpaEntity = entityManager.find(jpaEntityClass, id);
assertEquals(score, jpaEntity.getScore());
transaction.commit();
}

@MappedSuperclass
protected static abstract class AbstractTestJpaEntity<S extends Score> {

protected Long id;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}

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

@Transient
public abstract S getScore();
public abstract void setScore(S score);

}

@Entity
@TypeDef(name = "hardSoftScoreHibernateType", defaultForType = HardSoftScore.class, typeClass = HardSoftScoreHibernateType.class)
@TypeDef(defaultForType = HardSoftScore.class, typeClass = HardSoftScoreHibernateType.class)
public static class TestJpaEntity extends AbstractTestJpaEntity<HardSoftScore> {

protected HardSoftScore score;
Expand Down
Expand Up @@ -4,7 +4,7 @@
<persistence-unit name="optaplanner-persistence-jpa-test" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>

<class>org.optaplanner.persistence.jpa.impl.score.buildin.hardsoft.HardSoftScoreHibernateTypeTest$AbstractTestJpaEntity</class>
<class>org.optaplanner.persistence.jpa.impl.score.AbstractScoreHibernateTypeTest$AbstractTestJpaEntity</class>
<class>org.optaplanner.persistence.jpa.impl.score.buildin.hardsoft.HardSoftScoreHibernateTypeTest$TestJpaEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>

Expand Down

0 comments on commit 1080cbb

Please sign in to comment.