Search code examples
javaspringspring-bootspring-dataspring-el

Spring Expression Language (SpEL) access locale in Repository Query


I need to access current locale in Spring Repository using SpEL.

I have next Repository:

@Repository
public interface RoomRepository extends JpaRepository<Room, Long> {

    @Query(..."left join rc.roomClassTranslations rct on rct.language = ?#{SpEL expression})
    List<RoomDTO> findAllRooms(Sort sort);
}

I tried several expressions but none of them worked.

#{@localeResolver.resolveLocale(#httpServletRequest).toLanguageTag()} "...) In this expression httpServletRequest is null, if I change it to @httpServletRequest, it will give an error that no bean is found. I also tried to rewrite it like this

#{LocaleContextHolder.getLocale().toLanguageTag()} this will give next error:

EL1011E: Method call: Attempted to call method getLocale() on null context object.

So how to access current locale in SpEL expression?


Solution

  • Spring support the usage of restricted SpEL template expressions in manually defined queries that are defined with @Query.

    Spring Data exposes an extension point EvaluationContextExtension.

    Spring Data JPA will pick up all beans of type EvaluationContextExtension and use those to prepare the EvaluationContext to be used to evaluate the SpEL expression defined in @Query.

    Let's implement the locale extension as an example.
    @Component
    public class LocaleEvaluationContextExtension
            implements EvaluationContextExtension {
    
        @Override
        public Map<String, Object> getProperties() {
            Map<String, Object> properties = new HashMap<>(
                    EvaluationContextExtension.super.getProperties());
            return properties;
        }
    
        @Override
        public String getExtensionId() {
            return "locale";
        }
    
        @Override
        public Object getRootObject() {
            return LocaleContextHolder.getLocale();
        }
    }
    
    The query method definition should be:
    @Query(..."left join rc.roomClassTranslations rct on " +
            "rct.language = ?#{locale.language})
    List<RoomDTO> findAllRooms(Sort sort);