Giter VIP home page Giter VIP logo

Comments (7)

vruusmann avatar vruusmann commented on September 25, 2024 1

Another idea - maybe there is some Apache Maven plugin that can rewrite JPMML-Model classes (during the packaging phase of the build) by changing all field access modifiers from private to public.

This way the JPMML-Model library could stay as it is, and you could still have your "tweaked" variant of it.

from jpmml-model.

vruusmann avatar vruusmann commented on September 25, 2024 1

One final hurdle was to permit Maven to find MyClassTransformer on the classpath when executing the plugin.

@0xcfe4f1 Apache Maven plugins can declare their own "locally scoped" dependencies. For example, see https://github.com/jpmml/jpmml-model/blob/master/pmml-model/pom.xml#L195-L201

from jpmml-model.

vruusmann avatar vruusmann commented on September 25, 2024

What are your JDK and JPMML-Model library versions? How is your build configured, are you including the org.jpmml:pmml-model dependency, or the org.jpmml:pmml-model-metro dependency?

So maybe making some fields in class org.dmg.pmml.PMML public could help.

That would be a bad thing to do.

Anyway, you can relax the visibility of PMML class model fields in your application code using Java reflection API.

Something like this:

java.lang.reflect.Field[] fields = PMML.class.getDeclaredFields();
for(java.lang.reflect.Field field : fields){
	field.setAccessible(true);
}

You would need to do it before invoking the PMMLUtil#unmarshal(InputStream) method.

from jpmml-model.

vruusmann avatar vruusmann commented on September 25, 2024

Also, could be the case that RapidMiner uses some custom classloading mechanism, which interferes with JAXB unmarshaller. Can you parse the PMML file using a command-line application?

from jpmml-model.

kbruegge avatar kbruegge commented on September 25, 2024

Also, could be the case that RapidMiner uses some custom classloading mechanism, which
interferes with JAXB unmarshaller. Can you parse the PMML file using a command-line application?

It works fine from the command line.

Something like this:

java.lang.reflect.Field[] fields = PMML.class.getDeclaredFields();
for(java.lang.reflect.Field field : fields){
  field.setAccessible(true);
}

You would need to do it before invoking the PMMLUtil#unmarshal(InputStream) method.

This doesn't work because of the security manager I guess. It produces a java.security.AccessControlException

java.security.AccessControlException: access denied ("java.lang.reflect.ReflectPermission" "suppressAccessChecks")
	at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
	at java.security.AccessController.checkPermission(AccessController.java:884)
	at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
	at com.rapidminer.security.PluginSecurityManager.checkPermission(PluginSecurityManager.java:27)
	at java.lang.reflect.AccessibleObject.setAccessible(AccessibleObject.java:128)
	at de.woistbier.rapidminer.pmml.operator.PMMLEvaluator.read(PMMLEvaluator.java:120)
	at de.woistbier.rapidminer.pmml.operator.PMMLEvaluator.read(PMMLEvaluator.java:34)
	at com.rapidminer.operator.io.AbstractReader.doWork(AbstractReader.java:126)
	at com.rapidminer.operator.Operator.execute(Operator.java:1005)
	at com.rapidminer.operator.execution.SimpleUnitExecutor.execute(SimpleUnitExecutor.java:77)
	at com.rapidminer.operator.ExecutionUnit$3.run(ExecutionUnit.java:812)
	at com.rapidminer.operator.ExecutionUnit$3.run(ExecutionUnit.java:807)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.rapidminer.operator.ExecutionUnit.execute(ExecutionUnit.java:807)
	at com.rapidminer.operator.OperatorChain.doWork(OperatorChain.java:428)
	at com.rapidminer.operator.Operator.execute(Operator.java:1005)
	at com.rapidminer.Process.run(Process.java:1205)
	at com.rapidminer.Process.run(Process.java:1101)
	at com.rapidminer.Process.run(Process.java:1054)
	at com.rapidminer.Process.run(Process.java:1049)
	at com.rapidminer.Process.run(Process.java:1039)
	at com.rapidminer.gui.ProcessThread.run(ProcessThread.java:65)

from jpmml-model.

vruusmann avatar vruusmann commented on September 25, 2024

If it works from command-line, and not from within RapidMiner, then you should contact the RapidMiner team for technical assistance.

Most probably, RapidMiner's security manager is also preventing JAXB unmarshaller from doing its work - it should be the case that Sun/Oracle JAXB engine also uses Java reflection APIs to map XML and Java data structures.

The original JAXB error message is also an java.lang.IllegalAccessError. It's thrown when a Java field is not accessible, for example when the Field#setAccessible(true) was invoked, but didn't have any effect (in this case, the JAXB engine probably quietly swallowed the intermediate java.security.AccessControlException).

from jpmml-model.

0xcfe4f1 avatar 0xcfe4f1 commented on September 25, 2024

Another idea - maybe there is some Apache Maven plugin that can rewrite JPMML-Model classes (during the packaging phase of the build) by changing all field access modifiers from private to public.

This way the JPMML-Model library could stay as it is, and you could still have your "tweaked" variant of it.

Villu, your intuition here is correct, thank you for the hint.

I recently experienced this exact problem when trying to unmarshall PMML XML files at runtime with JAXB via org.jpmml.model.PMMLUtil.unmarshal(...) on a JVM with a very restrictive security policy in place.

I solved the problem by modifying the Maven POM build of my project with the following plugins:

  • maven-dependency-plugin - In the process-classes phase, configure this plugin to unpack the org.jpmml:pmml-model JAR dependency to the project target/classes path (required for the plugin below to manipulate the bytecode, as it can't reach inside JARs);
  • https://github.com/hielkehoeve/maven-javassist - In the process-classes phase, apply a custom Javassist transformer over classes in the org.dmg.pmml package to transform all declared field modifiers from protected/private to public (see below for my Javassist transformer implementation, MyClassTransformer);
  • maven-shade-plugin - In the package phase, construct a JAR by excluding any org.jpmml:pmml-model dependencies except those which were modified by the Javassist plugin above.

After packaging my code with this build configuration, JAXB successfully unmarshalls PMML XML at runtime without the exception above (java.lang.IllegalAccessError: Class com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$FieldReflection can not access a member of class org.dmg.pmml.PMML with modifiers "private").

The Javassist transformer implementation was straightforward:

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.Modifier;
import nl.topicus.plugins.maven.javassist.ClassTransformer;
import nl.topicus.plugins.maven.javassist.TransformationException;

public class MyClassTransformer extends ClassTransformer {
  @Override
  public void applyTransformations(ClassPool pool, CtClass clazz) throws TransformationException {
    for(CtField f : clazz.getDeclaredFields()) {
      f.setModifiers(Modifier.setPublic(f.getModifiers()));
    }
  }
}

One final hurdle was to permit Maven to find MyClassTransformer on the classpath when executing the plugin. I did this simply by using mvn install on a separate Maven project which packaged MyClassTransformer into its own group:artifact and added this as a new dependency to my main project where the plugin is called. (Edit: As Villu has pointed out, this can be added as a locally scoped dependency for the plugin instead of the whole project).

from jpmml-model.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.