Searching through enum set

Hi! I’m trying to implement indexing against set of enums.
(Java 21 Hibernate 7.3.0.Final Hibernate Search 8.3.0.Final)

public enum UserRole {
    ROLE_ADMIN,
    ROLE_EDITOR...
}
@Column( columnDefinition = "TEXT" )
@Convert( converter = UserRolesConverter.class )
//	@Enumerated(EnumType.STRING)
@PropertyBinding(
    binder = @PropertyBinderRef( type = UserRolesPropertyBinder.class )
)
private Set<UserRole> roles;

Enums are stored as a string rather than a collection in addtional table.

The problem is I don’t know how to add the bridge to the context.

public class UserRolesPropertyBinder
        implements PropertyBinder
{

	@Override
	public void bind( final PropertyBindingContext context ) {

		context.dependencies().useRootOnly();

		final UserRolePropertyBridge userRolesBridge =
			new UserRolePropertyBridge(
				context
					.indexSchemaElement()
					.field(
                        context.bridgedElement().name(),
                        f -> f.asString()
                    )
					.toReference()
			);

//-------------------------------------------------------
		context.bridge( ??????, userRolesBridge );
//-------------------------------------------------------

	}

    private static class UserRolePropertyBridge
            implements
                    PropertyBridge<Set<UserRole>>
    {

        private final IndexFieldReference<String> stringField;

        private UserRolePropertyBridge(
            final IndexFieldReference<String> stringField
        ) {
			this.stringField = stringField;
		}

		@Override
		public void write(
            final DocumentElement target,
            final Set<UserRole> userRoles,
            final PropertyBridgeWriteContext context
        ) {
			for( final UserRole role : userRoles ) {
				target.addValue( this.stringField, role.name() );
			}
		}

	}

}

Tried to find solution to employ TypeReference because Jackson has something similar which I use in converters, but couldn’t find any appropriate TypeReference to use here.

Once I fix ths, usage would be:

pf.match()
    .field( Field.USER_ROLES.getFieldName() ) // -> "roles"
    .matching( userRole )
    .toPredicate();

Is there a chance this solutio might work? Or I missed it in total?

Thanks!

P.S. Just for the record, another question of mine from the past, with similar theme:

Here is the converter just to provide all the information.

public class UserRolesConverter
        implements
            AttributeConverter< Set<UserRole>, String >,
            Serializable
{

    public static final TypeReference< Set<UserRole> > TYPE_REFERENCE = 
        new TypeReference<>() {
          //
        };

	@Override
	public String convertToDatabaseColumn( 
		final Set<UserRole> attribute 
	) {
		if (attribute == null || attribute.isEmpty()) {
			return null;
		}
		try {
			return 
				JacksonUtil.OBJECT_WRITER
					.writeValueAsString( attribute );
		}
		catch( final JsonProcessingException e ) {
			return null;
		}
	}

	@Override
	public Set<UserRole> convertToEntityAttribute( 
		final String dbData 
	) {

		if( dbData == null ) {
			return Collections.emptySet();
		}

		try {
			return 
				JacksonUtil.OBJECT_READER
					.forType( TYPE_REFERENCE )
					.readValue( dbData );
		}
		catch( final JsonProcessingException e ) {
			throw new IllegalStateException(
				"JsonProcessingException: " + e.getMessage()
			);
		}

	}

}

Maybe I’m missing something, but, uh… Why didn’t you simply go with this?

@Column( columnDefinition = "TEXT" )
@Convert( converter = UserRolesConverter.class )
//	@Enumerated(EnumType.STRING)
@KeywordField
private Set<UserRole> roles;

See:

I suppose you’re trying to achieve something different? What?

2 Likes

Yes, that fixed it. What to say, I’m not feeling smart right now. :rofl:

Thanks a million!