Aleksander Mielczarek
Aleksander Mielczarek

Reputation: 2825

Android and Hibernate Validator - it is possible to use together?

I wonder if it is possible to use Hibernate Validator on Android. I tried but it looks like some javax packages are missing on Android platform (javax.xml.stream.XMLInputFactory).

Here is my code, dependency and error:

ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();

compile 'org.hibernate:hibernate-validator:5.1.3.Final'
compile 'javax.el:javax.el-api:2.2.4'
compile 'org.glassfish.web:javax.el:2.2.4'

03-28 10:07:15.562    6477-6477/foo E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: foo, PID: 6477
    java.lang.NoClassDefFoundError: Failed resolution of: Ljavax/xml/stream/XMLInputFactory;
            at org.hibernate.validator.internal.xml.XmlParserHelper.<init>(XmlParserHelper.java:66)
            at org.hibernate.validator.internal.xml.ValidationXmlParser.<init>(ValidationXmlParser.java:60)
            at org.hibernate.validator.internal.engine.ConfigurationImpl.getBootstrapConfiguration(ConfigurationImpl.java:287)
            at org.hibernate.validator.internal.engine.ConfigurationImpl.parseValidationXml(ConfigurationImpl.java:361)
            at org.hibernate.validator.internal.engine.ConfigurationImpl.buildValidatorFactory(ConfigurationImpl.java:214)
            at javax.validation.Validation.buildDefaultValidatorFactory(Validation.java:110)
            at foo.FooActivity.onCreate(FooActivity.java:35)
            at android.app.Activity.performCreate(Activity.java:5933)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
            at android.app.ActivityThread.access$800(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "javax.xml.stream.XMLInputFactory" on path: DexPathList[[zip file "/data/app/foo-1/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
            at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
            at org.hibernate.validator.internal.xml.XmlParserHelper.<init>(XmlParserHelper.java:66)
            at org.hibernate.validator.internal.xml.ValidationXmlParser.<init>(ValidationXmlParser.java:60)
            at org.hibernate.validator.internal.engine.ConfigurationImpl.getBootstrapConfiguration(ConfigurationImpl.java:287)
            at org.hibernate.validator.internal.engine.ConfigurationImpl.parseValidationXml(ConfigurationImpl.java:361)
            at org.hibernate.validator.internal.engine.ConfigurationImpl.buildValidatorFactory(ConfigurationImpl.java:214)
            at javax.validation.Validation.buildDefaultValidatorFactory(Validation.java:110)
            at foo.FooActivity.onCreate(FooActivity.java:35)
            at android.app.Activity.performCreate(Activity.java:5933)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
            at android.app.ActivityThread.access$800(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
    Suppressed: java.lang.ClassNotFoundException: javax.xml.stream.XMLInputFactory
            at java.lang.Class.classForName(Native Method)
            at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
            at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
            ... 21 more
     Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available

Upvotes: 2

Views: 2036

Answers (1)

Aleksander Mielczarek
Aleksander Mielczarek

Reputation: 2825

I managed to solve this. Due to lack of xml packages we have to disable this option in configuration. Here is my proposed solution.

    ValidatorFactory validatorFactory = Validation
            .byDefaultProvider()
            .configure()
            .ignoreXmlConfiguration()
            .buildValidatorFactory();

    Validator validator = validatorFactory.getValidator();

It's necessary to have following dependencies:

compile 'org.hibernate:hibernate-validator:5.1.3.Final'
compile 'javax.el:javax.el-api:2.2.4'
compile 'org.glassfish.web:javax.el:2.2.4'

For custom messages from strings resources, MessageInterpolator has to be implemented. First of all Application must be extended for access to global context all over project.

public class ApplicationContext extends Application {
    private static Application application;

    @Override
    public void onCreate() {
        super.onCreate();
        application = this;
    }

    public static Application getApplication() {
        return application;
    }
}

Configuration:

    ValidatorFactory validatorFactory = Validation
            .byDefaultProvider()
            .configure()
            .ignoreXmlConfiguration()
            .messageInterpolator(new MessageInterpolator() {
                @Override
                public String interpolate(String messageTemplate, Context context) {
                    int id = ApplicationContext.getApplication().getResources().getIdentifier(messageTemplate, "string", R.class.getPackage().getName());
                    return ApplicationContext.getApplication().getString(id);
                }

                @Override
                public String interpolate(String messageTemplate, Context context, Locale locale) {
                    return interpolate(messageTemplate, context);
                }
            })
            .buildValidatorFactory();

Example:

@NotEmpty(message = "error_empty")
private String foo;

<resources>
    <string name="error_empty">Cannot be empty</string>
</resources>

Upvotes: 6

Related Questions