Skip to content

Commit

Permalink
HSEARCH-4673 Add test for projection records without -parameters comp…
Browse files Browse the repository at this point in the history
…iler flag
  • Loading branch information
marko-bekhta authored and yrodiere committed Oct 7, 2022
1 parent e7384ca commit 0f1c7d8
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 4 deletions.
Expand Up @@ -112,13 +112,16 @@ https://hibernate.atlassian.net/browse/HSEARCH-4577[at the moment].

Hibernate Search infers the path of the field to project on from the name of the corresponding constructor parameter.

You should set the name of a constructor parameter (in the Java code) to the name of the field to project on,
and make sure to compile your code with the `-parameters` compiler flag.
You should set the name of a constructor parameter (in the Java code) to the name of the field to project on.
For the canonical constructor of record types, you will not need to do anything else.
However, when using `@ProjectionConstructor` on non-record types or non-canonical constructors,
code must be compiled with the `-parameters` compiler flag.

[WARNING]
====
Projection types compiled without the `-parameters` compiler flag
will lead to exceptions on startup https://hibernate.atlassian.net/browse/HSEARCH-4574[at the moment].
Without the `-parameters` compiler flag,
errors will be thrown on startup as soon as `@ProjectionConstructor` is applied to a non-record type or a non-canonical constructor.
Hibernate Search may provide workarounds https://hibernate.atlassian.net/browse/HSEARCH-4574[in the future].
====

[[mapping-projection-multiple-constructors]]
Expand Down
4 changes: 4 additions & 0 deletions integrationtest/mapper/pojo-base/pom.xml
Expand Up @@ -19,6 +19,10 @@
<name>Hibernate Search ITs - POJO Mapper Base</name>
<description>Hibernate Search integration tests for the abstract base for POJO Mappers</description>

<properties>
<maven.compiler.testSources.noParameterCompilation.skip>false</maven.compiler.testSources.noParameterCompilation.skip>
</properties>

<dependencies>
<dependency>
<groupId>org.hibernate.search</groupId>
Expand Down
@@ -0,0 +1,145 @@
/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.integrationtest.mapper.pojo.mapping.definition;

import static org.assertj.core.api.Assertions.assertThat;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;

import org.hibernate.search.mapper.pojo.mapping.definition.annotation.DocumentId;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.GenericField;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ProjectionConstructor;
import org.hibernate.search.mapper.pojo.standalone.mapping.SearchMapping;
import org.hibernate.search.mapper.pojo.standalone.session.SearchSession;
import org.hibernate.search.util.impl.integrationtest.common.rule.BackendMock;
import org.hibernate.search.util.impl.integrationtest.common.rule.StubSearchWorkBehavior;
import org.hibernate.search.util.impl.integrationtest.mapper.pojo.standalone.StandalonePojoMappingSetupHelper;

import org.junit.Rule;
import org.junit.Test;

public class ProjectionConstructorRecordNoParametersCompilerFlagIT {

private static final String INDEX_NAME = "index_name";

@Rule
public BackendMock backendMock = new BackendMock();

@Rule
public StandalonePojoMappingSetupHelper setupHelper = StandalonePojoMappingSetupHelper.withBackendMock( MethodHandles.lookup(), backendMock );

@Test
public void sourcesCompiledWithoutParametersFlag() {
assertThat( ConstructorWithParameters.class.getDeclaredConstructors()[0].getParameters() )
.extracting( Parameter::isNamePresent )
.containsOnly( Boolean.FALSE, Boolean.FALSE );
}

@Test
public void typeLevelAnnotation() {
@Indexed(index = INDEX_NAME)
class IndexedEntity {
@DocumentId
public Integer id;
@FullTextField
public String text;
@GenericField
public Integer integer;
}
@ProjectionConstructor
record MyProjection(String text, Integer integer) { }

backendMock.expectAnySchema( INDEX_NAME );
SearchMapping mapping = setupHelper.start()
.withAnnotatedTypes( MyProjection.class )
.setup( IndexedEntity.class );
testSuccessfulRootProjection(
mapping, IndexedEntity.class, MyProjection.class,
Arrays.asList(
Arrays.asList( "result1", 1 ),
Arrays.asList( "result2", 2 ),
Arrays.asList( "result3", 3 )
),
Arrays.asList(
new MyProjection( "result1", 1 ),
new MyProjection( "result2", 2 ),
new MyProjection( "result3", 3 )
)
);
}

@Test
public void constructorLevelAnnotation_canonical() {
@Indexed(index = INDEX_NAME)
class IndexedEntity {
@DocumentId
public Integer id;
@FullTextField
public String text;
@GenericField
public Integer integer;
}
record MyProjection(String text, Integer integer) {
@ProjectionConstructor
public MyProjection {
}

public MyProjection(String text, Integer integer, String somethingElse) {
this( text, integer );
}
}

backendMock.expectAnySchema( INDEX_NAME );
SearchMapping mapping = setupHelper.start()
.withAnnotatedTypes( MyProjection.class )
.setup( IndexedEntity.class );
testSuccessfulRootProjection(
mapping, IndexedEntity.class, MyProjection.class,
Arrays.asList(
Arrays.asList( "result1", 1 ),
Arrays.asList( "result2", 2 ),
Arrays.asList( "result3", 3 )
),
Arrays.asList(
new MyProjection( "result1", 1 ),
new MyProjection( "result2", 2 ),
new MyProjection( "result3", 3 )
)
);
}

private <P> void testSuccessfulRootProjection(SearchMapping mapping, Class<?> indexedType, Class<P> projectionType,
List<?> rawProjectionResults, List<P> expectedProjectionResults) {
try ( SearchSession session = mapping.createSession() ) {
backendMock.expectSearchProjection(
INDEX_NAME,
StubSearchWorkBehavior.of(
rawProjectionResults.size(),
rawProjectionResults
)
);

assertThat( session.search( indexedType )
.select( projectionType )
.where( f -> f.matchAll() )
.fetchAllHits() )
.usingRecursiveFieldByFieldElementComparator()
.containsExactlyElementsOf( expectedProjectionResults );
}
backendMock.verifyExpectationsMet();
}

static class ConstructorWithParameters {
ConstructorWithParameters(int paramInt, String paramString) {
}
}
}
47 changes: 47 additions & 0 deletions pom.xml
Expand Up @@ -476,6 +476,12 @@
<maven.compiler.testSource>${maven.compiler.testRelease}</maven.compiler.testSource>
<maven.compiler.testTarget>${maven.compiler.testRelease}</maven.compiler.testTarget>

<!--
This is an explicit setting to control compiler plugin execution for the no `-parameters` flag case.
Needed as when `testIncludes` doesn't match any test classes, it brings all test sources and re-compiles them.
-->
<maven.compiler.testSources.noParameterCompilation.skip>true</maven.compiler.testSources.noParameterCompilation.skip>

<!--
Options to compile with the Eclipse compiler when building with maven (not with the IDE).
See profile "compiler-eclipse".
Expand Down Expand Up @@ -1611,6 +1617,18 @@
</sources>
</configuration>
</execution>
<execution>
<id>add-test-source-java17-noparameters</id>
<phase>${java-version.test.java17.add-test-source-phase}</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/test/java17-noparameters</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<!-- Skip the deploy plugin explicitly: we use nexus-staging-maven-plugin instead -->
Expand Down Expand Up @@ -1793,6 +1811,26 @@
<compilerArgs combine.self="append">
<compilerArg>-parameters</compilerArg>
</compilerArgs>
<testExcludes>
<testExclude>**/*NoParametersCompilerFlag*</testExclude>
</testExcludes>
</configuration>
</execution>
<execution>
<id>noparameters-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<skip>${maven.compiler.testSources.noParameterCompilation.skip}</skip>
<fork>true</fork>
<proc>none</proc>
<executable>${java-version.test.compiler}</executable>
<compilerArgs combine.self="override" />
<testIncludes>
<testInclude>**/*NoParametersCompilerFlag*</testInclude>
</testIncludes>
</configuration>
</execution>
</executions>
Expand Down Expand Up @@ -2616,6 +2654,15 @@
</compilerArgs>
</configuration>
</execution>
<execution>
<id>noparameters-testCompile</id>
<configuration>
<compilerArgs combine.children="append">
<!-- Ignore warnings that are too annoying for tests -->
<compilerArg>-warn:-unused,resource</compilerArg>
</compilerArgs>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
Expand Down

0 comments on commit 0f1c7d8

Please sign in to comment.