How to Install Locale in Bean Check

By default, Bean Validation gets Locale based on Locale.getDefault (), which is common to the entire JVM.

How to change the BeanValidation Locale for the current EJB method call?

I am using JavaEE7 and want to benefit from the integration of JPA and Bean Validation, i.e. Automatically check the operation when inserting / updating / deleting events and, as far as possible, avoid recording everything manually.

EDIT

In the end, I just return uninterpreted messages from the EJB:

public class DoNothingMessageInterpolator implements MessageInterpolator {
    @Override
    public String interpolate(String message, Context context) {
        return message;
    }
    @Override
    public String interpolate(String message, Context context, Locale locale) {
        return message;
    }
}

and then interpolate them in the web tier:

try{
    //invoke ejb
}catch( EJBException ejbex ){
    if( ejbex.getCause() instanceof ConstraintViolationException ){
        ConstraintViolationException cve = (ConstraintViolationException) ejbex.getCause();
        WebUtils.printConstraintViolationMessages("NewConferenceForm:", context, cve, new Locale(languageCtrl.getLocaleCode()) );
        return null;
    }else throw ejbex;
}catch( Exception e ){
        context.addMessage(null, new FacesMessage( FacesMessage.SEVERITY_ERROR, "Oops.", ""));
        return null;
}


public class WebUtils {

    public static void printConstraintViolationMessages(
        String formPrependId, 
        FacesContext context, 
        ConstraintViolationException cve,
        Locale locale )
    {
        Iterator<ConstraintViolation<?>> iter = cve.getConstraintViolations().iterator();
        while( iter.hasNext() ){
            final ConstraintViolation<?> cv = iter.next();

            javax.validation.MessageInterpolator.Context c = new javax.validation.MessageInterpolator.Context()
            {
                @Override public <T> T unwrap(Class<T> type) {
                    try {
                        return type.newInstance();
                    } catch (InstantiationException ex) {
                        Logger.getLogger(ConferencesCtrl.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (IllegalAccessException ex) {
                        Logger.getLogger(ConferencesCtrl.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    return null;
                }
                @Override
                public ConstraintDescriptor<?> getConstraintDescriptor() {
                    return cv.getConstraintDescriptor();
                }
                @Override
                public Object getValidatedValue() {
                    return cv.getInvalidValue();
                }
            };

            ResourceBundleMessageInterpolator rbmi = new ResourceBundleMessageInterpolator();
            String interpolatedMsg = rbmi.interpolate(cv.getMessage(), c, locale );

            //TODO: check if clientId exists
            context.addMessage( formPrependId+cv.getPropertyPath().toString(), new FacesMessage( interpolatedMsg ) );
        }
    }

}
+4
source share
2 answers

I think it comes down to what you really mean

How to change the BeanValidation Locale for the current EJB method call?

, , , , MessageInterpolator. validation.xml(. -).

, , . ResourceBundleMessageInterpolator Hibernate Validator Resource Resource Locale. ThreadLocaL. EJB Local ThreadLocal, .

+3

@Hardy, Local SessionContext MessageInterpolator.

bean . :

interface ILocale
{
    public Locale getLocale();
}

LocaleMessageInterpolator

MessageInterpolator . , EJB.

public class LocaleMessageInterpolator extends ResourceBundleMessageInterpolator
{
    private final ILocale iLocale;

    public LocaleMessageInterpolator(final ILocale iLocale)
    {
        this.iLocale = iLocale;
    }

    @Override
    public String interpolate(final String messageTemplate, final Context context)
    {
        final Locale locale = this.iLocale == null ? null : this.iLocale.getLocale();

        if (locale == null)
            return super.interpolate(messageTemplate, context);
        else
            return this.interpolate(messageTemplate, context, locale);
    }
}

bean

MessageInterpolator factory. Beans AppBean, setClientLocale().

@Startup
@Singleton
public class AppBean
{
    public static final String CONTEXT_CLIENT_LOCALE_KEY =  "CLIENT_LOCALE_KEY";

    @Resource
    private SessionContext ctx;

    @PostConstruct
    public void init()
    {
        // retrieve client locale from context using anyonymous implementation
        final ILocale ilocale = () -> {
            if (AppBean.this.ctx.getContextData().containsKey(AppBean.CONTEXT_CLIENT_LOCALE_KEY))
                return (Locale) AppBean.this.ctx.getContextData()
                .get(AppBean.CONTEXT_CLIENT_LOCALE_KEY);
            return null;
        };

        // create client locale aware message interpolator
        final LocaleMessageInterpolator localeMessageInterpolator= new LocaleMessageInterpolator(ilocale);

        // configurate validator factory
        ValidatorFactory validatorFactory = Validation.byDefaultProvider().configure().messageInterpolator(localeMessageInterpolator).buildValidatorFactory();

        // register validator factory

configuration.getProperties(). put ( "javax.persistence.validation.factory", validatorFactory);       }

bean

SessionContext.

@Stateless(mappedName = "MyBean")
@Remote(MyBeanRemote.class)
public class MyBean
{
    @Resource
    private SessionContext ctx;

    @Override
    public void create(Locale locale, Foo foo)
    {
        this.ctx.getContextData().put(AppBean.CONTEXT_CLIENT_LOCALE_KEY, locale);
        // persist new Foo
        // thrown validation exceptions are localized
    }
}
+2

Source: https://habr.com/ru/post/1536607/


All Articles