/* * Hibernate, Relational Persistence for Idiomatic Java * * JBoss, Home of Professional Open Source * Copyright 2012 Red Hat Inc. and/or its affiliates and other contributors * as indicated by the @authors tag. All rights reserved. * See the copyright.txt in the distribution for a * full listing of individual contributors. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * 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, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.hibernate.search.test.configuration; import java.lang.annotation.ElementType; import java.util.Arrays; import junit.framework.Assert; import org.apache.lucene.search.Query; import org.hibernate.search.SearchException; import org.hibernate.search.annotations.ProvidedId; import org.hibernate.search.backend.spi.Work; import org.hibernate.search.backend.spi.WorkType; import org.hibernate.search.cfg.SearchMapping; import org.hibernate.search.engine.spi.SearchFactoryImplementor; import org.hibernate.search.query.dsl.QueryBuilder; import org.hibernate.search.spi.SearchFactoryBuilder; import org.hibernate.search.test.util.ManualConfiguration; import org.hibernate.search.test.util.ManualTransactionContext; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; /** * By overriding {@link org.hibernate.search.cfg.spi.SearchConfiguration#isIdProvidedImplicit()} * we allow to assume entities are annotated with ProvidedId. * * @author Sanne Grinovero <sanne@hibernate.org> (C) 2012 Red Hat Inc. */ public class ImplicitProvidedIdTest { @Rule public ExpectedException exceptions = ExpectedException.none(); @Test public void exceptionThrownWhenNotEnabled() { SearchMapping mapping = new SearchMapping(); mapping .entity( Book.class ).indexed() //Entity missing both @DocumentId and @ProvidedId: .property( "title", ElementType.FIELD ).field() .property( "text", ElementType.FIELD ).field() ; ManualConfiguration cfg = new ManualConfiguration() .addProperty( "hibernate.search.default.directory_provider", "ram" ) .setProgrammaticMapping( mapping ) .addClass( Book.class ); exceptions.expect( SearchException.class ); exceptions.expectMessage( "No document id in: " + Book.class.getName() ); storeBooksViaProvidedId( cfg, ProvidedId.defaultFieldName, false ); } @Test public void usingConfigurationTypeOverride() { SearchMapping mapping = new SearchMapping(); mapping .entity( Book.class ).indexed() //Entity missing both @DocumentId and @ProvidedId: .property( "title", ElementType.FIELD ).field() .property( "text", ElementType.FIELD ).field() ; ManualConfiguration cfg = new ManualConfiguration() .addProperty( "hibernate.search.default.directory_provider", "ram" ) .setProgrammaticMapping( mapping ) .setIdProvidedImplicit( true ) .addClass( Book.class ); storeBooksViaProvidedId( cfg, ProvidedId.defaultFieldName, false ); } @Test public void usingProvidedIdAsOptionsOverride() { SearchMapping mapping = new SearchMapping(); mapping .entity( Book.class ).indexed() .providedId().name( "myID" ) //Entity missing both @DocumentId and @ProvidedId: .property( "title", ElementType.FIELD ).field() .property( "text", ElementType.FIELD ).field() ; ManualConfiguration cfg = new ManualConfiguration() .addProperty( "hibernate.search.default.directory_provider", "ram" ) .setProgrammaticMapping( mapping ) .setIdProvidedImplicit( true ) .addClass( Book.class ); storeBooksViaProvidedId( cfg, "myID", false ); } @Test public void usingExplicitProvidedId() { SearchMapping mapping = new SearchMapping(); mapping .entity( Book.class ).indexed() .providedId().name( "myID" ) //Entity missing both @DocumentId and @ProvidedId: .property( "title", ElementType.FIELD ).field() .property( "text", ElementType.FIELD ).field() ; ManualConfiguration cfg = new ManualConfiguration() .addProperty( "hibernate.search.default.directory_provider", "ram" ) .setProgrammaticMapping( mapping ) .setIdProvidedImplicit( false ) //DEFAULT .addClass( Book.class ); storeBooksViaProvidedId( cfg, "myID", false ); } @Test public void usingDefaultSettings() { SearchMapping mapping = new SearchMapping(); mapping .entity( Book.class ).indexed() .providedId().name( "myID" ) //Entity missing both @DocumentId and @ProvidedId: .property( "title", ElementType.FIELD ).field() .property( "text", ElementType.FIELD ).field() ; ManualConfiguration cfg = new ManualConfiguration() .addProperty( "hibernate.search.default.directory_provider", "ram" ) .setProgrammaticMapping( mapping ) //.setIdProvidedImplicit( false ) //Test it's the default .addClass( Book.class ); storeBooksViaProvidedId( cfg, "myID", false ); } @Test public void documentIdNotOverriden() { SearchMapping mapping = new SearchMapping(); mapping .entity( Book.class ).indexed() .property( "title", ElementType.FIELD ).documentId() .property( "text", ElementType.FIELD ).field() ; ManualConfiguration cfg = new ManualConfiguration() .addProperty( "hibernate.search.default.directory_provider", "ram" ) .setProgrammaticMapping( mapping ) //.setIdProvidedImplicit( false ) //Test it's the default .addClass( Book.class ); storeBooksViaProvidedId( cfg, "title", true ); } /** * @param cfg The SearchFactory configuration to be tested * @param fieldName The expected name of the ID field */ private void storeBooksViaProvidedId(ManualConfiguration cfg, String fieldName, boolean matchTitle) { SearchFactoryImplementor sf = null; try { //Should fail right here when @ProvidedId is not enabled: sf = new SearchFactoryBuilder().configuration( cfg ).buildSearchFactory(); Book book = new Book(); book.title = "Less is nice"; book.text = "When using Infinispan Query, users have to always remember to add @ProvidedId on their classes" + " or a nasty exception will remind them. Can't we just assume it's always annotated?"; String isbn = "some entity-external id"; Work work = new Work( book, isbn, WorkType.ADD, false ); ManualTransactionContext tc = new ManualTransactionContext(); sf.getWorker().performWork( work, tc ); tc.end(); QueryBuilder queryBuilder = sf.buildQueryBuilder() .forEntity( Book.class ) .get(); Query query = queryBuilder.keyword() .onField( fieldName ) .ignoreAnalyzer() .matching( matchTitle ? book.title : isbn ) .createQuery(); int queryResultSize = sf.createHSQuery() .luceneQuery( query ) .targetedEntities( Arrays.asList( new Class<?>[]{ Book.class } ) ) .queryResultSize(); Assert.assertEquals( 1, queryResultSize ); } finally { if ( sf != null ) { sf.close(); } } } /** * Test entity. We use programmatic configuration to test different annotation combinations. */ static class Book { String title; String text; } }