/*
* 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.engine.metadata.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.lucene.document.Field;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XMember;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.search.analyzer.Discriminator;
import org.hibernate.search.analyzer.spi.AnalyzerReference;
import org.hibernate.search.analyzer.spi.ScopedAnalyzerReference;
import org.hibernate.search.bridge.LuceneOptions;
import org.hibernate.search.engine.BoostStrategy;
import org.hibernate.search.engine.impl.MutableAnalyzerRegistry;
import org.hibernate.search.engine.impl.ConfigContext;
import org.hibernate.search.engine.impl.LuceneOptionsImpl;
import org.hibernate.search.exception.SearchException;
import org.hibernate.search.indexes.spi.IndexManagerType;
import org.hibernate.search.util.StringHelper;
import org.hibernate.search.util.logging.impl.Log;
import org.hibernate.search.util.logging.impl.LoggerFactory;
/**
* Class containing all the meta data extracted for a single type ( and all classes in its hierarchy ).
*
* @author Hardy Ferentschik
*/
public class TypeMetadata {
private static final Log log = LoggerFactory.make();
private static final String COMPONENT_PATH_SEPARATOR = ".";
/**
* The type for this metadata
*/
private final Class<?> indexedType;
/**
* The class boost for this type (class level @Boost)
*/
private final float boost;
/**
* Optional analyzer discriminator. There can only be one per class.
*/
private final Discriminator discriminator;
/**
* {@code AnalyzerDiscriminator} can be defined on class level or on property. In the latter case this is the member
* on which it is defined.
*/
private final XMember discriminatorGetter;
/**
* Optional dynamic boost strategy.
*/
private final BoostStrategy classBoostStrategy;
/**
* Set of all Java property (field or getter) metadata instances
*/
private final Set<PropertyMetadata> propertyMetadata;
/**
* Metadata for all document fields.
* <p>This does not include document fields from embedded types.
*/
private final Set<DocumentFieldMetadata> documentFieldMetadata;
/**
* Metadata for a document field keyed against the field absolute name.
* <p>This does not include document fields from embedded types.
* <p><strong>Caution</strong>: this may not include every document metadata, most notably
* because document fields generated for class bridges may not have a name, and there may
* be multiple ones (so only the last one is present in the map).
*/
private final Map<String, DocumentFieldMetadata> documentFieldNameToFieldMetadata;
/**
* Metadata for a bridge-defined field keyed against the field absolute name.
*/
private final Map<String, BridgeDefinedField> bridgeDefinedFieldNameToFieldMetadata;
/**
* Metadata for a facet keyed against the facet field name
*/
private final Map<String, FacetMetadata> facetFieldNameToFacetMetadata;
/**
* Metadata for a Java property (field or getter) keyed against the property name.
*/
private final Map<String, PropertyMetadata> propertyGetterNameToPropertyMetadata;
/**
* The property metadata for the id getter. {@code null} for non indexed types ( indexed embedded only )
*/
private final PropertyMetadata idPropertyMetadata;
/**
* Set of field meta data instances contributed by class bridges
*/
private final Set<DocumentFieldMetadata> classBridgeFields;
/**
* Document field metadata keyed against the field absolute name.
* <p>These fields are contributed by class bridges.
*/
private final Map<String, DocumentFieldMetadata> classBridgeFieldNameToDocumentFieldMetadata;
/**
* Metadata of embedded types ({@code @IndexedEmbedded})
*/
private final Set<EmbeddedTypeMetadata> embeddedTypeMetadata;
/**
* List of contained in properties ({@code @ContainedIn})
*/
private final Set<ContainedInMetadata> containedInMetadata;
/**
* The scoped analyzer reference for this entity
*/
private final ScopedAnalyzerReference scopedAnalyzerReference;
/**
* Whether we can optimize the indexing work by inspecting the changed fields
*/
private boolean stateInspectionOptimizationsEnabled;
/**
* Encountered property names of field, embedded and contained in collections. Used to optimize indexing based
* on ORM collection update events.
*/
private final Set<String> collectionRoles;
/**
* Flag indicating whether the JPA @Id is used as document id. See {@link org.hibernate.search.engine.impl.WorkPlan}
*/
// TODO - would be nice to not need this in TypeMetadata (HF)
private final boolean jpaIdUsedAsDocumentId;
/**
* List of classes discovered during metadata processing for which collection event optimizations needs to be
* disabled.
*/
// TODO - would be nice to not need this in TypeMetadata (HF)
private final Set<XClass> optimizationBlackList;
private final Set<SortableFieldMetadata> classBridgeSortableFieldMetadata;
protected TypeMetadata(Builder builder) {
this.indexedType = builder.indexedType;
this.boost = builder.boost;
this.scopedAnalyzerReference = builder.scopedAnalyzerReferenceBuilder == null ? null
: builder.scopedAnalyzerReferenceBuilder.build();
this.discriminator = builder.discriminator;
this.discriminatorGetter = builder.discriminatorGetter;
this.classBoostStrategy = builder.classBoostStrategy;
this.stateInspectionOptimizationsEnabled = builder.stateInspectionOptimizationsEnabled;
this.idPropertyMetadata = builder.idPropertyMetadata;
this.embeddedTypeMetadata = Collections.unmodifiableSet( builder.embeddedTypeMetadata );
this.containedInMetadata = Collections.unmodifiableSet( builder.containedInMetadata );
this.optimizationBlackList = Collections.unmodifiableSet( builder.optimizationClassList );
this.collectionRoles = Collections.unmodifiableSet( builder.collectionRoles );
this.jpaIdUsedAsDocumentId = determineWhetherDocumentIdPropertyIsTheSameAsJpaIdProperty( builder.jpaProperty );
this.classBridgeFields = Collections.unmodifiableSet( builder.classBridgeFields );
this.propertyMetadata = Collections.unmodifiableSet( builder.propertyMetadataSet );
this.propertyGetterNameToPropertyMetadata = buildPropertyMetadataMap( builder.propertyMetadataSet );
this.documentFieldMetadata = collectFieldMetadata( builder.propertyMetadataSet, builder.classBridgeFields, builder.idPropertyMetadata );
this.documentFieldNameToFieldMetadata = buildFieldMetadataMap( documentFieldMetadata );
this.facetFieldNameToFacetMetadata = buildFacetMetadataMap( documentFieldMetadata );
this.bridgeDefinedFieldNameToFieldMetadata = buildBridgeDefinedFieldMetadataMap( documentFieldNameToFieldMetadata.values() );
this.classBridgeFieldNameToDocumentFieldMetadata = copyClassBridgeMetadata( builder.classBridgeFields );
this.classBridgeSortableFieldMetadata = Collections.unmodifiableSet( builder.classBridgeSortableFieldMetadata );
}
public Class<?> getType() {
return indexedType;
}
public Set<PropertyMetadata> getAllPropertyMetadata() {
return propertyMetadata;
}
public PropertyMetadata getPropertyMetadataForProperty(String propertyName) {
return propertyGetterNameToPropertyMetadata.get( propertyName );
}
public PropertyMetadata getIdPropertyMetadata() {
return idPropertyMetadata;
}
public Set<DocumentFieldMetadata> getClassBridgeMetadata() {
return classBridgeFields;
}
public Set<SortableFieldMetadata> getClassBridgeSortableFieldMetadata() {
return classBridgeSortableFieldMetadata;
}
public DocumentFieldMetadata getDocumentFieldMetadataFor(String fieldName) {
DocumentFieldMetadata result = documentFieldNameToFieldMetadata.get( fieldName );
if ( result != null ) {
return result;
}
for ( EmbeddedTypeMetadata element : embeddedTypeMetadata ) {
result = element.getDocumentFieldMetadataFor( fieldName );
if ( result != null ) {
return result;
}
}
return null;
}
public BridgeDefinedField getBridgeDefinedFieldMetadataFor(String fieldName) {
BridgeDefinedField result = bridgeDefinedFieldNameToFieldMetadata.get( fieldName );
if ( result != null ) {
return result;
}
for ( EmbeddedTypeMetadata element : embeddedTypeMetadata ) {
result = element.getBridgeDefinedFieldMetadataFor( fieldName );
if ( result != null ) {
return result;
}
}
return null;
}
public FacetMetadata getFacetMetadataFor(String facetFieldName) {
FacetMetadata result = facetFieldNameToFacetMetadata.get( facetFieldName );
if ( result != null ) {
return result;
}
for ( EmbeddedTypeMetadata element : embeddedTypeMetadata ) {
result = element.getFacetMetadataFor( facetFieldName );
if ( result != null ) {
return result;
}
}
return null;
}
/**
* Return all {@link DocumentFieldMetadata}.
* Instances are not duplicated in the collection. We use {@code Collection} instead of {@code Set} for
* implementation reasons.
* @return all {@link DocumentFieldMetadata}
*/
public Collection<DocumentFieldMetadata> getAllDocumentFieldMetadata() {
if ( embeddedTypeMetadata.isEmpty() ) {
return documentFieldMetadata;
}
else {
Collection<DocumentFieldMetadata> allMetadata = new ArrayList<DocumentFieldMetadata>(
documentFieldMetadata.size()
);
for ( EmbeddedTypeMetadata element : embeddedTypeMetadata ) {
allMetadata.addAll( element.getAllDocumentFieldMetadata() );
}
allMetadata.addAll( documentFieldMetadata );
return Collections.unmodifiableCollection( allMetadata );
}
}
public Collection<DocumentFieldMetadata> getNonEmbeddedDocumentFieldMetadata() {
return documentFieldMetadata;
}
// TODO HSEARCH-1867 change return type to set
public List<EmbeddedTypeMetadata> getEmbeddedTypeMetadata() {
return Collections.unmodifiableList( new ArrayList<EmbeddedTypeMetadata>( embeddedTypeMetadata ) );
}
public Set<ContainedInMetadata> getContainedInMetadata() {
return containedInMetadata;
}
public Collection<XClass> getOptimizationBlackList() {
return optimizationBlackList;
}
public boolean containsCollectionRole(String role) {
for ( String knownRolls : collectionRoles ) {
if ( isSubRole( knownRolls, role ) ) {
return true;
}
}
return false;
}
public boolean areClassBridgesUsed() {
return !classBridgeFieldNameToDocumentFieldMetadata.isEmpty();
}
public DocumentFieldMetadata getFieldMetadataForClassBridgeField(String fieldName) {
return classBridgeFieldNameToDocumentFieldMetadata.get( fieldName );
}
public Discriminator getDiscriminator() {
return discriminator;
}
public XMember getDiscriminatorGetter() {
return discriminatorGetter;
}
public boolean areStateInspectionOptimizationsEnabled() {
return stateInspectionOptimizationsEnabled;
}
public void disableStateInspectionOptimizations() {
stateInspectionOptimizationsEnabled = false;
}
public LuceneOptions getClassLuceneOptions(DocumentFieldMetadata fieldMetadata, float documentLevelBoost) {
return new LuceneOptionsImpl( fieldMetadata, 1f, documentLevelBoost );
}
public LuceneOptions getFieldLuceneOptions(PropertyMetadata propertyMetadata,
DocumentFieldMetadata fieldMetadata,
Object value, float inheritedBoost) {
return new LuceneOptionsImpl(
fieldMetadata,
fieldMetadata.getBoost() * propertyMetadata.getDynamicBoostStrategy().defineBoost( value ),
inheritedBoost
);
}
public BoostStrategy getDynamicBoost() {
return classBoostStrategy;
}
public float getStaticBoost() {
return boost;
}
public float getClassBoost(Object value) {
return boost * classBoostStrategy.defineBoost( value );
}
public ScopedAnalyzerReference getDefaultAnalyzerReference() {
return scopedAnalyzerReference;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder( "TypeMetadata{" );
sb.append( "boost=" ).append( boost );
sb.append( ", discriminator=" ).append( discriminator );
sb.append( ", discriminatorGetter=" ).append( discriminatorGetter );
sb.append( ", classBoostStrategy=" ).append( classBoostStrategy );
sb.append( ", documentFieldNameToFieldMetadata=" ).append( documentFieldNameToFieldMetadata );
sb.append( ", propertyGetterNameToFieldMetadata=" ).append( propertyGetterNameToPropertyMetadata );
sb.append( ", idPropertyMetadata=" ).append( idPropertyMetadata );
sb.append( ", classBridgeFields=" ).append( classBridgeFieldNameToDocumentFieldMetadata );
sb.append( ", embeddedTypeMetadata=" ).append( embeddedTypeMetadata );
sb.append( ", containedInMetadata=" ).append( containedInMetadata );
sb.append( ", optimizationBlackList=" ).append( optimizationBlackList );
sb.append( ", stateInspectionOptimizationsEnabled=" ).append( stateInspectionOptimizationsEnabled );
sb.append( ", scopedAnalyzerReference=" ).append( scopedAnalyzerReference );
sb.append( ", collectionRoles=" ).append( collectionRoles );
sb.append( '}' );
return sb.toString();
}
private boolean isSubRole(String subRole, String role) {
if ( role.equals( subRole ) ) {
return true; // direct match
}
if ( role.startsWith( subRole + COMPONENT_PATH_SEPARATOR ) ) {
return true; // role == subRole.<something>
}
return false;
}
private boolean determineWhetherDocumentIdPropertyIsTheSameAsJpaIdProperty(XProperty jpaIdProperty) {
if ( idPropertyMetadata == null ) {
return false; // not an indexed type
}
if ( jpaIdProperty == null ) {
return false;
}
else {
return jpaIdProperty.equals( idPropertyMetadata.getPropertyAccessor() );
}
}
private Map<String, PropertyMetadata> buildPropertyMetadataMap(Set<PropertyMetadata> propertyMetadataSet) {
Map<String, PropertyMetadata> tmpMap = new LinkedHashMap<String, PropertyMetadata>();
for ( PropertyMetadata propertyMetadata : propertyMetadataSet ) {
tmpMap.put( propertyMetadata.getPropertyAccessorName(), propertyMetadata );
}
return Collections.unmodifiableMap( tmpMap );
}
private Set<DocumentFieldMetadata> collectFieldMetadata(Set<PropertyMetadata> propertyMetadataSet,
Set<DocumentFieldMetadata> classBridgeFields, PropertyMetadata idPropertyMetadata) {
Set<DocumentFieldMetadata> tmpSet = new LinkedHashSet<DocumentFieldMetadata>(); // Preserve order to make buildFieldMetadataMap deterministic
for ( PropertyMetadata propertyMetadata : propertyMetadataSet ) {
for ( DocumentFieldMetadata documentFieldMetadata : propertyMetadata.getFieldMetadataSet() ) {
tmpSet.add( documentFieldMetadata );
}
}
for ( DocumentFieldMetadata documentFieldMetadata : classBridgeFields ) {
tmpSet.add( documentFieldMetadata );
}
if ( idPropertyMetadata != null ) {
for ( DocumentFieldMetadata documentFieldMetadata : idPropertyMetadata.getFieldMetadataSet() ) {
tmpSet.add( documentFieldMetadata );
}
}
return Collections.unmodifiableSet( tmpSet );
}
private Map<String, DocumentFieldMetadata> buildFieldMetadataMap(Set<DocumentFieldMetadata> documentFieldMetadataSet) {
Map<String, DocumentFieldMetadata> tmpMap = new LinkedHashMap<String, DocumentFieldMetadata>();
for ( DocumentFieldMetadata documentFieldMetadata : documentFieldMetadataSet ) {
String name = documentFieldMetadata.getAbsoluteName();
if ( StringHelper.isEmpty( name ) ) {
continue;
}
DocumentFieldMetadata oldFieldMetadata = tmpMap.put( name, documentFieldMetadata );
if ( oldFieldMetadata != null ) {
if ( !documentFieldMetadata.getIndex().equals( oldFieldMetadata.getIndex() ) ) {
// Try to use the actual declaring type, if possible
PropertyMetadata sourceProperty = documentFieldMetadata.getSourceProperty();
String sourceTypeName = sourceProperty != null
? sourceProperty.getPropertyAccessor().getDeclaringClass().getName()
: documentFieldMetadata.getSourceType().getType().getName();
log.inconsistentFieldConfiguration( sourceTypeName, name );
}
}
}
return Collections.unmodifiableMap( tmpMap );
}
private Map<String, FacetMetadata> buildFacetMetadataMap(Collection<DocumentFieldMetadata> documentFieldMetadataCollection) {
Map<String, FacetMetadata> tmpMap = new LinkedHashMap<String, FacetMetadata>();
for ( DocumentFieldMetadata documentFieldMetadata : documentFieldMetadataCollection ) {
for ( FacetMetadata facetMetadata : documentFieldMetadata.getFacetMetadata() ) {
tmpMap.put( facetMetadata.getAbsoluteName(), facetMetadata );
}
}
// Class bridge fields, etc. are already included in documentFieldMetadataCollection
return Collections.unmodifiableMap( tmpMap );
}
private Map<String, BridgeDefinedField> buildBridgeDefinedFieldMetadataMap(Collection<DocumentFieldMetadata> documentFieldMetadataCollection) {
Map<String, BridgeDefinedField> tmpMap = new LinkedHashMap<String, BridgeDefinedField>();
for ( DocumentFieldMetadata documentFieldMetadata : documentFieldMetadataCollection ) {
for ( BridgeDefinedField bridgeDefinedField : documentFieldMetadata.getBridgeDefinedFields().values() ) {
tmpMap.put( bridgeDefinedField.getAbsoluteName(), bridgeDefinedField );
}
}
// Class bridge fields, etc. are already included in documentFieldMetadataCollection
return Collections.unmodifiableMap( tmpMap );
}
private Map<String, DocumentFieldMetadata> copyClassBridgeMetadata(Set<DocumentFieldMetadata> classBridgeFields) {
Map<String, DocumentFieldMetadata> tmpMap = new LinkedHashMap<String, DocumentFieldMetadata>();
for ( DocumentFieldMetadata fieldMetadata : classBridgeFields ) {
tmpMap.put( fieldMetadata.getAbsoluteName(), fieldMetadata );
}
return Collections.unmodifiableMap( tmpMap );
}
public boolean isJpaIdUsedAsDocumentId() {
return jpaIdUsedAsDocumentId;
}
public static class Builder {
protected final BackReference<TypeMetadata> resultReference = new BackReference<>();
private final Class<?> indexedType;
private final ScopedAnalyzerReference.Builder scopedAnalyzerReferenceBuilder;
private final MutableAnalyzerRegistry analyzerRegistry;
private float boost;
private BoostStrategy classBoostStrategy;
private Discriminator discriminator;
private XMember discriminatorGetter;
private boolean stateInspectionOptimizationsEnabled = true;
private final Set<PropertyMetadata> propertyMetadataSet = new LinkedHashSet<>();
private final Set<DocumentFieldMetadata> classBridgeFields = new LinkedHashSet<DocumentFieldMetadata>();
private final Set<EmbeddedTypeMetadata> embeddedTypeMetadata = new LinkedHashSet<EmbeddedTypeMetadata>();
private final Set<ContainedInMetadata> containedInMetadata = new LinkedHashSet<ContainedInMetadata>();
private final Set<XClass> optimizationClassList = new LinkedHashSet<XClass>();
private final Set<String> collectionRoles = new TreeSet<String>();
private PropertyMetadata idPropertyMetadata;
private XProperty jpaProperty;
private final Set<SortableFieldMetadata> classBridgeSortableFieldMetadata = new LinkedHashSet<>();
public Builder(Class<?> indexedType, ConfigContext configContext, ParseContext parseContext) {
this.indexedType = indexedType;
if ( parseContext.skipAnalyzers() ) {
this.analyzerRegistry = null;
this.scopedAnalyzerReferenceBuilder = null;
}
else {
IndexManagerType indexManagerType = parseContext.getIndexManagerType();
this.analyzerRegistry = configContext.getAnalyzerRegistry( indexManagerType );
this.scopedAnalyzerReferenceBuilder = analyzerRegistry.buildScopedAnalyzerReference();
}
}
public Builder(Class<?> indexedType, Builder containerTypeBuilder) {
this.indexedType = indexedType;
this.analyzerRegistry = containerTypeBuilder.analyzerRegistry;
this.scopedAnalyzerReferenceBuilder = containerTypeBuilder.scopedAnalyzerReferenceBuilder;
}
public Builder idProperty(PropertyMetadata propertyMetadata) {
this.idPropertyMetadata = propertyMetadata;
return this;
}
public Builder boost(float boost) {
this.boost = boost;
return this;
}
public Builder boostStrategy(BoostStrategy boostStrategy) {
this.classBoostStrategy = boostStrategy;
return this;
}
public Builder analyzerReference(AnalyzerReference analyzerReference) {
this.scopedAnalyzerReferenceBuilder.setGlobalAnalyzerReference( analyzerReference );
return this;
}
public Builder jpaProperty(XProperty jpaProperty) {
this.jpaProperty = jpaProperty;
return this;
}
public Builder analyzerDiscriminator(Discriminator discriminator, XMember discriminatorGetter) {
if ( this.discriminator != null ) {
throw new SearchException(
"Multiple AnalyzerDiscriminator defined in the same class hierarchy: " + this.indexedType
.getName()
);
}
this.discriminator = discriminator;
this.discriminatorGetter = discriminatorGetter;
return this;
}
public Builder addProperty(PropertyMetadata propertyMetadata) {
if ( idPropertyMetadata != null && idPropertyMetadata.getPropertyAccessorName() != null ) {
// the id property is always a single field
String idFieldName = idPropertyMetadata.getFieldMetadataSet().iterator().next().getAbsoluteName();
for ( DocumentFieldMetadata fieldMetadata : propertyMetadata.getFieldMetadataSet() ) {
if ( idFieldName.equals( fieldMetadata.getAbsoluteName() ) ) {
throw log.fieldTriesToOverrideIdFieldSettings(
propertyMetadata.getPropertyAccessor().getDeclaringClass().getName(),
propertyMetadata.getPropertyAccessor().getName()
);
}
}
}
this.propertyMetadataSet.add( propertyMetadata );
return this;
}
public void addClassBridgeField(DocumentFieldMetadata fieldMetadata) {
classBridgeFields.add( fieldMetadata );
}
public void addEmbeddedType(EmbeddedTypeMetadata embeddedTypeMetadata) {
this.embeddedTypeMetadata.add( embeddedTypeMetadata );
}
public void addContainedIn(ContainedInMetadata containedInMetadata) {
this.containedInMetadata.add( containedInMetadata );
}
public void addCollectionRole(String role) {
collectionRoles.add( role );
}
public void disableStateInspectionOptimization() {
stateInspectionOptimizationsEnabled = false;
}
@SuppressWarnings( "deprecation" )
public AnalyzerReference addToScopedAnalyzerReference(DocumentFieldPath fieldPath, AnalyzerReference analyzerReference, Field.Index index) {
if ( analyzerReference == null ) {
analyzerReference = scopedAnalyzerReferenceBuilder.getGlobalAnalyzerReference();
}
if ( !index.isAnalyzed() ) {
// no analyzer is used, add a pass-through (i.e. no-op) analyzer for queries
analyzerReference = analyzerRegistry.getPassThroughAnalyzerReference();
}
scopedAnalyzerReferenceBuilder.addAnalyzerReference( fieldPath.getAbsoluteName(), analyzerReference );
return analyzerReference;
}
public void blacklistForOptimization(XClass blackListClass) {
this.optimizationClassList.add( blackListClass );
}
public boolean areClassBridgesUsed() {
return !classBridgeFields.isEmpty();
}
public BoostStrategy getClassBoostStrategy() {
return classBoostStrategy;
}
public AnalyzerReference getAnalyzerReference() {
return scopedAnalyzerReferenceBuilder.getGlobalAnalyzerReference();
}
public ScopedAnalyzerReference.Builder getScopedAnalyzerReferenceBuilder() {
return scopedAnalyzerReferenceBuilder;
}
public boolean isStateInspectionOptimizationsEnabled() {
return stateInspectionOptimizationsEnabled;
}
public Class<?> getIndexedType() {
return indexedType;
}
public PropertyMetadata getIdPropertyMetadata() {
return idPropertyMetadata;
}
public BackReference<TypeMetadata> getResultReference() {
return resultReference;
}
public TypeMetadata build() {
TypeMetadata result = new TypeMetadata( this );
resultReference.initialize( result );
return result;
}
@Override
public String toString() {
return "TypeMetadata.Builder{indexedType=" + indexedType + "}";
}
public void addClassBridgeSortableFields(Iterable<String> sortableFieldsAbsoluteNames) {
for ( String sortableFieldAbsoluteName : sortableFieldsAbsoluteNames ) {
classBridgeSortableFieldMetadata.add( new SortableFieldMetadata.Builder( sortableFieldAbsoluteName ).build() );
}
}
}
}