Java tutorial
/* * The MIT License * * Copyright 2013 Jakub Jirutka <jakub@jirutka.cz>. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package cz.jirutka.rsql.hibernate; import cz.jirutka.rsql.hibernate.builder.AbstractCriterionBuilder; import cz.jirutka.rsql.hibernate.builder.CriteriaBuilder; import cz.jirutka.rsql.hibernate.exception.ArgumentFormatException; import cz.jirutka.rsql.hibernate.exception.AssociationsLimitException; import cz.jirutka.rsql.hibernate.exception.RSQLException; import cz.jirutka.rsql.hibernate.exception.UnknownSelectorException; import org.hibernate.impl.CriteriaImpl.Subcriteria; import cz.jirutka.rsql.hibernate.RSQL2CriteriaConverterImpl.InnerBuilder; import org.hibernate.Criteria; import cz.jirutka.rsql.hibernate.entity.Course; import cz.jirutka.rsql.parser.model.Comparison; import cz.jirutka.rsql.parser.model.ComparisonExpression; import cz.jirutka.rsql.parser.model.Expression; import cz.jirutka.rsql.parser.model.Logical; import cz.jirutka.rsql.parser.model.LogicalExpression; import java.util.Iterator; import org.hibernate.SessionFactory; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.DetachedCriteria; import org.hibernate.criterion.Restrictions; import org.hibernate.impl.CriteriaImpl; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Jakub Jirutka <jakub@jirutka.cz> */ public class RSQL2CriteriaConverterImplTest { private SessionFactory sessionFactory; private Mapper mapper; private RSQL2CriteriaConverterImpl instance; private InnerBuilder inner; @Before public void setUp() throws Exception { sessionFactory = SessionFactoryInitializer.getSessionFactory(); mapper = new Mapper() { @Override public String translate(String selector, Class<?> entityClass) { return selector; } }; instance = new MockRSQL2CriteriaConverterImpl(sessionFactory); instance.setMapper(mapper); instance.pushCriterionBuilder(new MockCriterionBuilder()); inner = ((MockRSQL2CriteriaConverterImpl) instance).createInnerBuilder(Course.class); } ////////////////////////// Tests ////////////////////////// /** * Test if single comparison expression is routed to Criterion Builder well. */ @Test public void testInnerConvertDetached0() { instance.setMapper(mapper); instance.pushCriterionBuilder(new MockCriterionBuilder() { @Override public Criterion createCriterion(String property, Comparison operator, String argument, Class<?> entityClass, String alias, CriteriaBuilder parent) throws ArgumentFormatException, UnknownSelectorException { assertEquals("foo", property); assertEquals(operator, Comparison.EQUAL); assertEquals("bar", argument); assertEquals(Course.class, entityClass); assertEquals("this.", alias); assertNotNull(parent); throw new AssertionError("This should be thrown!"); } }); Expression expression = new ComparisonExpression("foo", Comparison.EQUAL, "bar"); try { inner.convert(expression, DetachedCriteria.forClass(Course.class)); fail("Method createCriterion() was not called!"); } catch (AssertionError ex) { /*OK*/ } } /** * Test if composite expression is routed to Criterion Builder well. */ @Test public void testInnerConvertDetached1() { instance.setMapper(mapper); instance.pushCriterionBuilder(new MockCriterionBuilder() { int call = 0; @Override public Criterion createCriterion(String property, Comparison operator, String argument, Class<?> entityClass, String alias, CriteriaBuilder parent) throws ArgumentFormatException, UnknownSelectorException { if (call == 0) { assertEquals("sel0", property); assertEquals(operator, Comparison.EQUAL); assertEquals("foo", argument); } else if (call == 1) { assertEquals("sel1", property); assertEquals(operator, Comparison.NOT_EQUAL); assertEquals("bar", argument); } else if (call == 2) { assertEquals("sel2", property); assertEquals(operator, Comparison.LESS_THAN); assertEquals("baz", argument); throw new AssertionError("This should be thrown!"); } assertNotNull(parent); call++; return Restrictions.eq("null", "null"); } }); Expression expression = new LogicalExpression( new LogicalExpression(new ComparisonExpression("sel0", Comparison.EQUAL, "foo"), Logical.OR, new ComparisonExpression("sel1", Comparison.NOT_EQUAL, "bar")), Logical.AND, new ComparisonExpression("sel2", Comparison.LESS_THAN, "baz")); try { inner.convert(expression, DetachedCriteria.forClass(Course.class)); fail("Method createCriterion() was not called for third time!"); } catch (AssertionError ex) { /*OK*/ } } /** * Finally test whole DetachedCriteria creation. */ @Test public void testInnerConvertDetached2() { instance.pushCriterionBuilder(new MockCriterionBuilder()); DetachedCriteria expResult = DetachedCriteria.forClass(Course.class, RSQL2CriteriaConverter.ROOT_ALIAS) .add(Restrictions.and(Restrictions.eq("foo", "flynn"), Restrictions.or(Restrictions.eq("bar", 42), Restrictions.eq("baz", 42.2)))); Expression expression = new LogicalExpression(new ComparisonExpression("foo", Comparison.EQUAL, "flynn"), Logical.AND, new LogicalExpression(new ComparisonExpression("bar", Comparison.EQUAL, "42"), Logical.OR, new ComparisonExpression("baz", Comparison.EQUAL, "42.2"))); DetachedCriteria result = DetachedCriteria.forClass(Course.class); inner.convert(expression, result); assertEquals(expResult.toString(), result.toString()); } @Test public void testCreateCriteria2arg() { DetachedCriteria expResult; expResult = DetachedCriteria.forClass(Course.class, RSQL2CriteriaConverter.ROOT_ALIAS) .add(Restrictions.eq("foo", "bar")); DetachedCriteria result = instance.createCriteria("foo==bar", Course.class); assertEquals("Expression: foo==bar", expResult.toString(), result.toString()); try { instance.createCriteria("invalid input ", Course.class); fail("Should raise RSQLException"); } catch (RSQLException ex) { /* OK */ } } @Test public void testPushCriterionBuilder() { MockRSQL2CriteriaConverterImpl converter = new MockRSQL2CriteriaConverterImpl(sessionFactory); converter.setMapper(mapper); converter.pushCriterionBuilder(new MockCriterionBuilder() { @Override public Criterion createCriterion(String property, Comparison operator, String argument, Class<?> entityClass, String alias, CriteriaBuilder parent) throws ArgumentFormatException, UnknownSelectorException { fail("Should be at the bottom of builders stack"); return null; } }); converter.pushCriterionBuilder(new MockCriterionBuilder() { @Override public Criterion createCriterion(String property, Comparison operator, String argument, Class<?> entityClass, String alias, CriteriaBuilder parent) throws ArgumentFormatException, UnknownSelectorException { // ok return Restrictions.ne("foo", "notbar"); } }); converter.pushCriterionBuilder(new MockCriterionBuilder() { @Override public boolean accept(String selector, Class<?> entityClass, CriteriaBuilder parent) { return false; } @Override public Criterion createCriterion(String property, Comparison operator, String argument, Class<?> entityClass, String alias, CriteriaBuilder parent) throws ArgumentFormatException, UnknownSelectorException { fail("Should not be accepted"); return null; } }); Expression expression = new ComparisonExpression("foo", Comparison.EQUAL, "bar"); DetachedCriteria expResult = DetachedCriteria.forClass(Course.class).add(Restrictions.ne("foo", "notbar")); DetachedCriteria result = DetachedCriteria.forClass(Course.class); converter.createInnerBuilder(Course.class).convert(expression, result); assertEquals(expResult.toString(), result.toString()); } @Test public void testCreateAssociationAlias() { final String aliasPrefix = RSQL2CriteriaConverter.ALIAS_PREFIX; instance.setAssociationsLimit(3); instance.pushCriterionBuilder(new MockCriterionBuilder() { @Override public Criterion createCriterion(String property, Comparison operator, String argument, Class<?> entityClass, String alias, CriteriaBuilder parent) throws ArgumentFormatException, UnknownSelectorException { assertEquals(aliasPrefix + "1", parent.createAssociationAlias("foo", Criteria.INNER_JOIN)); assertEquals(aliasPrefix + "2", parent.createAssociationAlias("bar", Criteria.LEFT_JOIN)); assertEquals(aliasPrefix + "1", parent.createAssociationAlias("foo", Criteria.LEFT_JOIN)); assertEquals(aliasPrefix + "3", parent.createAssociationAlias("baz", Criteria.FULL_JOIN)); try { parent.createAssociationAlias("qux"); fail("Should raise JoinsLimitException"); } catch (AssociationsLimitException ex) { /*OK*/ } throw new AssertionError("This should be thrown!"); } }); Criteria criteria = sessionFactory.openSession().createCriteria(Course.class); Expression expression = new ComparisonExpression("foo", Comparison.EQUAL, "bar"); try { inner.convert(expression, criteria); fail("Method createCriterion() was not called!"); } catch (AssertionError ex) { /*OK*/ } int i = 0; Iterator<Subcriteria> it = ((CriteriaImpl) criteria).iterateSubcriteria(); while (it.hasNext()) { Subcriteria sub = it.next(); switch (i) { case 0: { assertEquals("foo", sub.getPath()); assertEquals("alias1", sub.getAlias()); assertEquals(Criteria.INNER_JOIN, sub.getJoinType()); break; } case 1: { assertEquals("bar", sub.getPath()); assertEquals("alias2", sub.getAlias()); assertEquals(Criteria.LEFT_JOIN, sub.getJoinType()); break; } case 2: { assertEquals("baz", sub.getPath()); assertEquals("alias3", sub.getAlias()); assertEquals(Criteria.FULL_JOIN, sub.getJoinType()); break; } default: fail("Should not be here!"); } i++; } assertEquals("Should iterate over three subcriterias", 3, i); } @Test public void testLoadAssociationAliases() { Expression expression = new ComparisonExpression("foo", Comparison.EQUAL, "bar"); instance.pushCriterionBuilder(new MockCriterionBuilder() { @Override public Criterion createCriterion(String property, Comparison operator, String argument, Class<?> entityClass, String alias, CriteriaBuilder parent) throws ArgumentFormatException, UnknownSelectorException { assertEquals("givenAlias1", parent.createAssociationAlias("foo")); assertEquals("givenAlias3", parent.createAssociationAlias("baz")); assertEquals("givenAlias2", parent.createAssociationAlias("bar")); throw new AssertionError("This should be thrown!"); } }); Criteria criteria1 = sessionFactory.openSession().createCriteria(Course.class) .createAlias("foo", "givenAlias1").createAlias("bar", "givenAlias2") .createAlias("baz", "givenAlias3"); try { inner.convert(expression, criteria1); fail("Method createCriterion() was not called!"); } catch (AssertionError ex) { /*OK*/ } Criteria criteria2 = sessionFactory.openSession().createCriteria(Course.class) .createCriteria("foo", "givenAlias1").createCriteria("bar", "givenAlias2") .createCriteria("baz", "givenAlias3"); try { inner.convert(expression, criteria2); fail("Method createCriterion() was not called!"); } catch (AssertionError ex) { /*OK*/ } } ////////////////////////// Mocks ////////////////////////// private static class MockRSQL2CriteriaConverterImpl extends RSQL2CriteriaConverterImpl { public MockRSQL2CriteriaConverterImpl(SessionFactory sessionFactory) { super(sessionFactory); } public InnerBuilder createInnerBuilder(Class<?> entityClass) { return new InnerBuilder(entityClass); } } private static class MockCriterionBuilder extends AbstractCriterionBuilder { @Override public boolean accept(String property, Class<?> entityClass, CriteriaBuilder parent) { return true; } @Override public Criterion createCriterion(String property, Comparison operator, String argument, Class<?> entityClass, String alias, CriteriaBuilder parent) throws ArgumentFormatException, UnknownSelectorException { return Restrictions.eq(property, argument); } } }