Skip to content

Commit

Permalink
HSEARCH-2415 Unify the way we take adaptors into account when introsp…
Browse files Browse the repository at this point in the history
…ecting bridges
  • Loading branch information
yrodiere authored and Sanne committed Dec 19, 2016
1 parent f45fbeb commit c40651f
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 28 deletions.
Expand Up @@ -13,8 +13,8 @@

import org.hibernate.search.bridge.FieldBridge;
import org.hibernate.search.bridge.builtin.NumericFieldBridge;
import org.hibernate.search.bridge.builtin.impl.NullEncodingTwoWayFieldBridge;
import org.hibernate.search.bridge.spi.FieldType;
import org.hibernate.search.bridge.util.impl.BridgeAdaptorUtils;
import org.hibernate.search.engine.metadata.impl.BridgeDefinedField;
import org.hibernate.search.engine.metadata.impl.DocumentFieldMetadata;
import org.hibernate.search.engine.metadata.impl.PropertyMetadata;
Expand Down Expand Up @@ -228,12 +228,7 @@ public static boolean isNumeric(DocumentFieldMetadata field) {
}

FieldBridge fieldBridge = field.getFieldBridge();

if ( fieldBridge instanceof NullEncodingTwoWayFieldBridge ) {
return ( (NullEncodingTwoWayFieldBridge) fieldBridge ).unwrap() instanceof NumericFieldBridge;
}

return false;
return BridgeAdaptorUtils.unwrapAdaptorOnly( fieldBridge, NumericFieldBridge.class ) != null;
}

public static String[] getFieldNameParts(String fieldName) {
Expand Down
Expand Up @@ -11,12 +11,13 @@
import org.hibernate.search.bridge.FieldBridge;
import org.hibernate.search.bridge.LuceneOptions;
import org.hibernate.search.bridge.StringBridge;
import org.hibernate.search.bridge.util.impl.BridgeAdaptor;
import org.hibernate.search.bridge.util.impl.String2FieldBridgeAdaptor;

/**
* @author Davide D'Alto
*/
public class NullEncodingFieldBridge implements FieldBridge, StringBridge {
public class NullEncodingFieldBridge implements FieldBridge, StringBridge, BridgeAdaptor {

private final String2FieldBridgeAdaptor bridge;
private final String nullMarker;
Expand Down Expand Up @@ -49,4 +50,9 @@ public String objectToString(Object object) {
return bridge.objectToString( object );
}

@Override
public Object unwrap() {
return bridge;
}

}
Expand Up @@ -13,14 +13,15 @@
import org.apache.lucene.search.Query;
import org.hibernate.search.bridge.LuceneOptions;
import org.hibernate.search.bridge.TwoWayFieldBridge;
import org.hibernate.search.bridge.util.impl.BridgeAdaptor;
import org.hibernate.search.engine.impl.nullencoding.NullMarkerCodec;
import org.hibernate.search.util.logging.impl.Log;
import org.hibernate.search.util.logging.impl.LoggerFactory;

/**
* @author Hardy Ferentschik
*/
public class NullEncodingTwoWayFieldBridge implements TwoWayFieldBridge {
public class NullEncodingTwoWayFieldBridge implements TwoWayFieldBridge, BridgeAdaptor {

private static final Log LOG = LoggerFactory.make();

Expand Down Expand Up @@ -58,6 +59,7 @@ public String objectToString(Object object) {
}
}

@Override
public TwoWayFieldBridge unwrap() {
return fieldBridge;
}
Expand Down
@@ -0,0 +1,29 @@
/*
* 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.bridge.util.impl;

import org.hibernate.search.bridge.TwoWayStringBridge;
import org.hibernate.search.bridge.spi.IgnoreAnalyzerBridge;

/**
* An interface for bridge adaptors, i.e. types exposing one bridge interface and using
* another bridge instance under the hood.
*
* <p>Implementing this interface allows {@link BridgeAdaptorUtils} to detect
* specific bridge interfaces ({@link TwoWayStringBridge}, {@link IgnoreAnalyzerBridge},
* ...) even when the adaptor does no re-implement the interface.
*
* @author Yoann Rodiere
*/
public interface BridgeAdaptor {

/**
* @return The bridge that is directly wrapped by this adaptor.
*/
Object unwrap();

}
@@ -0,0 +1,86 @@
/*
* 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.bridge.util.impl;

import org.hibernate.search.bridge.ContainerBridge;
import org.hibernate.search.bridge.TwoWayStringBridge;
import org.hibernate.search.bridge.spi.IgnoreAnalyzerBridge;

/**
* Utilities allowing to take into account bridge adaptors when detecting implemented tagging
* interface (e.g. {@link IgnoreAnalyzerBridge}) or when trying to make use of specific field
* interfaces (e.g. {@link TwoWayStringBridge}).
*
* @author Yoann Rodiere
*/
public final class BridgeAdaptorUtils {

private BridgeAdaptorUtils() {
// private constructor
}

/**
* Return a bridge of the specified type extracted from the given bridge,
* going through {@link BridgeAdaptor adaptors} and {@link ContainerBridge container bridges}
* as necessary.
*
* <p>The returned object may be the adaptor itself, or its delegate, or a delegate of
* its delegate, and so on.
* <p>If neither the adaptor or one of its delegates is an instance of the specified type,
* {@code null} is returned.
*
* @param bridge The bridge to use as a starting point.
* @param clazz The expected bridge type.
* @return A unwrapped bridge implementing the expected bridge type, or {@code null}
* if none could be found.
*/
public static <T> T unwrapAdaptorAndContainer(Object bridge, Class<T> clazz) {
if ( clazz.isInstance( bridge ) ) {
return clazz.cast( bridge );
}
else if ( bridge instanceof BridgeAdaptor ) {
Object delegate = ( (BridgeAdaptor) bridge ).unwrap();
return unwrapAdaptorAndContainer( delegate, clazz );
}
else if ( bridge instanceof ContainerBridge ) {
Object delegate = ( (ContainerBridge) bridge ).getElementBridge();
return unwrapAdaptorAndContainer( delegate, clazz );
}
else {
return null;
}
}

/**
* Return a bridge of the specified type extracted from the given bridge,
* going through {@link BridgeAdaptor adaptors} as necessary, never going
* through {@link ContainerBridge container bridges}.
*
* <p>The returned object may be the adaptor itself, or its delegate, or a delegate of
* its delegate, and so on.
* <p>If neither the adaptor or one of its delegates is an instance of the specified type,
* {@code null} is returned.
*
* @param bridge The bridge to use as a starting point.
* @param clazz The expected bridge type.
* @return A unwrapped bridge implementing the expected bridge type, or {@code null}
* if none could be found.
*/
public static <T> T unwrapAdaptorOnly(Object bridge, Class<T> clazz) {
if ( clazz.isInstance( bridge ) ) {
return clazz.cast( bridge );
}
else if ( bridge instanceof BridgeAdaptor ) {
Object delegate = ( (BridgeAdaptor) bridge ).unwrap();
return unwrapAdaptorOnly( delegate, clazz );
}
else {
return null;
}
}

}
Expand Up @@ -11,10 +11,10 @@

import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.hibernate.search.bridge.ContainerBridge;
import org.hibernate.search.bridge.FieldBridge;
import org.hibernate.search.bridge.builtin.NumericEncodingDateBridge;
import org.hibernate.search.bridge.builtin.NumericFieldBridge;
import org.hibernate.search.bridge.builtin.impl.NullEncodingTwoWayFieldBridge;
import org.hibernate.search.bridge.builtin.time.impl.NumericTimeBridge;
import org.hibernate.search.bridge.impl.JavaTimeBridgeProvider;
import org.hibernate.search.util.logging.impl.Log;
Expand Down Expand Up @@ -149,11 +149,21 @@ public static boolean requiresNumericRangeQuery(Object value) {
* @return true if the considered {@code FieldBridge} is a numeric {@code FieldBridge}
*/
public static boolean isNumericFieldBridge(FieldBridge fieldBridge) {
if ( fieldBridge instanceof NullEncodingTwoWayFieldBridge ) {
fieldBridge = ( (NullEncodingTwoWayFieldBridge) fieldBridge ).unwrap();
}
return fieldBridge instanceof NumericFieldBridge
|| fieldBridge instanceof NumericTimeBridge
|| fieldBridge instanceof NumericEncodingDateBridge;
return BridgeAdaptorUtils.unwrapAdaptorOnly( fieldBridge, NumericFieldBridge.class ) != null
|| BridgeAdaptorUtils.unwrapAdaptorOnly( fieldBridge, NumericTimeBridge.class ) != null
|| BridgeAdaptorUtils.unwrapAdaptorOnly( fieldBridge, NumericEncodingDateBridge.class ) != null;
}

/**
* Indicates whether the considered {@code FieldBridge}, or its {@link ContainerBridge#getElementBridge() element bridge},
* is a numeric one.
*
* @param fieldBridge the considered {@code FieldBridge}
* @return true if the considered {@code FieldBridge} is a numeric {@code FieldBridge}
*/
public static boolean isNumericContainerOrNumericFieldBridge(FieldBridge fieldBridge) {
return BridgeAdaptorUtils.unwrapAdaptorAndContainer( fieldBridge, NumericFieldBridge.class ) != null
|| BridgeAdaptorUtils.unwrapAdaptorAndContainer( fieldBridge, NumericTimeBridge.class ) != null
|| BridgeAdaptorUtils.unwrapAdaptorAndContainer( fieldBridge, NumericEncodingDateBridge.class ) != null;
}
}
Expand Up @@ -19,7 +19,7 @@
* @author Emmanuel Bernard (C) 2011 Red Hat Inc.
* @author Sanne Grinovero (C) 2011 Red Hat Inc.
*/
public class String2FieldBridgeAdaptor implements FieldBridge, StringBridge, AppliedOnTypeAwareBridge {
public class String2FieldBridgeAdaptor implements FieldBridge, StringBridge, AppliedOnTypeAwareBridge, BridgeAdaptor {
private final StringBridge stringBridge;

public String2FieldBridgeAdaptor(StringBridge stringBridge) {
Expand Down Expand Up @@ -52,4 +52,9 @@ public void setAppliedOnType(Class<?> returnType) {
( (AppliedOnTypeAwareBridge) stringBridge ).setAppliedOnType( returnType );
}
}

@Override
public Object unwrap() {
return stringBridge;
}
}
Expand Up @@ -45,6 +45,7 @@ public Object get(String name, Document document) {
}
}

@Override
public TwoWayStringBridge unwrap() {
return stringBridge;
}
Expand Down
Expand Up @@ -1388,16 +1388,9 @@ else if ( String.class.isAssignableFrom( indexedType ) ) {
}

private boolean isNumericField(NumericField numericFieldAnnotation, FieldBridge fieldBridge) {
if ( fieldBridge instanceof ContainerBridge ) {
fieldBridge = ( (ContainerBridge) fieldBridge ).getElementBridge();
}
if ( fieldBridge instanceof NullEncodingTwoWayFieldBridge ) {
fieldBridge = ( (NullEncodingTwoWayFieldBridge) fieldBridge ).unwrap();
}

// either @NumericField is specified explicitly or we are dealing with a implicit numeric value encoded via a numeric
// field bridge
return numericFieldAnnotation != null || NumericFieldUtils.isNumericFieldBridge( fieldBridge );
return numericFieldAnnotation != null || NumericFieldUtils.isNumericContainerOrNumericFieldBridge( fieldBridge );
}

private NumericEncodingType determineNumericFieldEncoding(FieldBridge fieldBridge) {
Expand Down
Expand Up @@ -25,6 +25,7 @@
import org.hibernate.search.bridge.builtin.impl.NullEncodingTwoWayFieldBridge;
import org.hibernate.search.bridge.spi.ConversionContext;
import org.hibernate.search.bridge.spi.IgnoreAnalyzerBridge;
import org.hibernate.search.bridge.util.impl.BridgeAdaptorUtils;
import org.hibernate.search.bridge.util.impl.ContextualExceptionBridgeHelper;
import org.hibernate.search.bridge.util.impl.NumericFieldUtils;
import org.hibernate.search.engine.spi.DocumentBuilderIndexedEntity;
Expand Down Expand Up @@ -104,9 +105,7 @@ private Query createQuery(FieldContext fieldContext, ConversionContext conversio
validateNullValueIsSearchable( fieldContext );
final String searchTerm = buildSearchTerm( fieldContext, documentBuilder, conversionContext );

if ( !applyTokenization || fieldBridge instanceof IgnoreAnalyzerBridge ||
(fieldBridge instanceof NullEncodingTwoWayFieldBridge
&& ((NullEncodingTwoWayFieldBridge) fieldBridge).unwrap() instanceof IgnoreAnalyzerBridge ) ) {
if ( !applyTokenization || BridgeAdaptorUtils.unwrapAdaptorOnly( fieldBridge, IgnoreAnalyzerBridge.class ) != null ) {
perFieldQuery = createTermQuery( fieldContext, searchTerm );
}
else {
Expand Down

0 comments on commit c40651f

Please sign in to comment.