When I tried using XStream 1.4.9 to serialize an IllegalArgumentException type variable, there is a java.lang.UnsupportedOperationException.
Below is the stack trace information.
I have no idea what this could mean. Information from online is limited.
java.lang.UnsupportedOperationException: Not supported. Pass in the cause using the constructors instead.
at com.oracle.truffle.api.exception.AbstractTruffleException.initCause(AbstractTruffleException.java:413)
at com.thoughtworks.xstream.converters.extended.ThrowableConverter.marshal(ThrowableConverter.java:56)
at com.thoughtworks.xstream.core.AbstractReferenceMarshaller.convert(AbstractReferenceMarshaller.java:68)
try {
final ScriptEngine scriptEngine = new ScriptEngineManager()
.getEngineByName("JavaScript");
Objects.toString(scriptEngine.eval("X"), null);
} catch (Exception e) {
XStream xstream = new XStream();
System.err.println(xstream.toXML(e));
}
This is a minimum example that I see.
I realize that whenever I used js-scriptengine dependency, XStream fails to serialize it, while removing such dependency, everything works
I think it's due to Graalvm's implementation of "javax.script.ScriptEngine" class, which are not implemented as what jdk has implemented.
Removing Graalvm dependency, everything works fine.
Related
Security framework of XStream not initialized, XStream is probably vulnerable
I keep getting this console error in red while using XStream (1.4.10)
I tried the following:
XStream.setupDefaultSecurity(xs);
and
xs.addPermission(AnyTypePermission.ANY);
xs.addPermission(NoTypePermission.NONE);
none of which got rid of it.
I do not need any fancy security settings, I just want to silence that warning. Maybe also prepare the code for 1.5.x
When dealing with security issues, I wouldn't take it lightly. Firstly one would understand the severity of the issue, here a good write up or another one.
Then find out how people recommend the solution. The good place to start is from xstream website itself. There is an example which you can use as a starting point on xstream security page.
This would be my set up which basically allows most of your code.
XStream xstream = new XStream();
// clear out existing permissions and set own ones
xstream.addPermission(NoTypePermission.NONE);
// allow some basics
xstream.addPermission(NullPermission.NULL);
xstream.addPermission(PrimitiveTypePermission.PRIMITIVES);
xstream.allowTypeHierarchy(Collection.class);
// allow any type from the same package
xstream.allowTypesByWildcard(new String[] {
"com.your.package.**"
});
However, after diving more into their source code, this is my take:
XStream.setupDefaultSecurity(this); // to be removed after 1.5
xstream.allowTypesByWildcard(new String[] {
"com.your.package.**"
});
So essentially, you will need just one line once upgrading to 1.5.
Please note that you may need more wild cards to suit your application deserialization scenarios. This is not a one-size-fit-all answer but rather a good starting point IMHO.
I had the same "problem" and solved it by allowing the relevant types:
Class<?>[] classes = new Class[] { ABC.class, XYZ.class };
XStream xStream = new XStream();
XStream.setupDefaultSecurity(xStream);
xStream.allowTypes(classes);
Maybe this also helps in your case.
Good luck!
It also works by specifying an all-inclusive pattern for allowed classes:
xstream.allowTypesByRegExp(new String[] { ".*" });
To anyone who comes across this, it's likely due to CVE-2021-21351
XStream has a RCE vulnerability in earlier versions. You should upgrade to 1.46.1 or higher immediately.
I'm trying to determine the best way to create a new instance of a class based on which classes are available on the classpath at runtime.
For example, I have a library that requires a JSON response to be parsed in multiple classes. The library has the following interface:
JsonParser.java:
public interface JsonParser {
<T> T fromJson(String json, Class<T> type);
<T> String toJson(T object);
}
This class has multiple implementations, i.e. GsonJsonParser, JacksonJsonParser, Jackson2JsonParser, and currently, the user of the library is required to "pick" their implementation to be used based on which library they've included in their project. For example:
JsonParser parser = new GsonJsonParser();
SomeService service = new SomeService(parser);
What I'd like to do, is dynamically pick up which library is on the classpath, and create the proper instance, so that the user of the library doesn't have to think about it (or even have to know the internal implementation of another class parses JSON).
I'm considering something similar to the following:
try {
Class.forName("com.google.gson.Gson");
return new GsonJsonParser();
} catch (ClassNotFoundException e) {
// Gson isn't on classpath, try next implementation
}
try {
Class.forName("com.fasterxml.jackson.databind.ObjectMapper");
return new Jackson2JsonParser();
} catch (ClassNotFoundException e) {
// Jackson 2 was not found, try next implementation
}
// repeated for all implementations
throw new IllegalStateException("You must include either Gson or Jackson on your classpath to utilize this library");
Would this be an appropriate solution? It seems kind of like a hack, as well as uses exceptions to control the flow.
Is there a better way to do this?
Essentially you want to create your own JsonParserFactory. We can see how it's implemented in the Spring Boot framework:
public static JsonParser getJsonParser() {
if (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", null)) {
return new JacksonJsonParser();
}
if (ClassUtils.isPresent("com.google.gson.Gson", null)) {
return new GsonJsonParser();
}
if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) {
return new YamlJsonParser();
}
return new BasicJsonParser();
}
So your approach is nearly the same as this, except for the use of the ClassUtils.isPresent method.
This sounds like a perfect case for the Service Provider Interface (SPI) pattern. Check out the java.util.ServiceLoader documentation for an example of how to implement it.
If only one of the implementations (GsonJsonParser, JacksonJsonParser, Jackson2JsonParser) would be present at runtime and there is no other option, then you'd have to use Class.forName().
Although you can handle it a smarter.
For example, you can put all the classes into a Set<String> and then loop over them. If any one of them throws exception, you can just continue, and the one which does not, you can do your operations.
Yes, it is a hack, and your code would become library dependent. If there could be any chance that you can include all three implementations of your JsonParsers in your classpath and use a logic to define which implementation you have to use; that would be a much better approach.
If this is not possible, you can continue with above.
Also, instead of using plain Class.forName(String name), you can use a better option Class.forName(String name, boolean initialize, ClassLoader loader) which will NOT run any static initializers (if present in your class).
Where initialize = false and loader = [class].getClass().getClassLoader()
The simple approach is the one SLF4J uses: create a separate wrapper library per underlying JSON library (GSON, Jackson, etc.) with a com.mypackage.JsonParserImpl class that delegates to the underlying library. Put the appropriate wrapper in the classpath alongside the underlying library. Then you can get the current implementation like:
public JsonParser getJsonParser() {
// needs try block
// also, you probably want to cache
return Class.forName("com.mypackage.JsonParserImpl").newInstance()
}
This approach uses the class loader to locate the JSON parser. It is the simplest and requires no 3rd party dependencies or frameworks. I see no drawbacks to it relative to Spring, Service Provider, or any other method of locating resources.
Alternately use the Service Provider API, as Daniel Pryden suggests. To do this, you still create a separate wrapper library per underlying JSON library. Each library includes a text file at location "META-INF/services/com.mypackage.JsonParser" whose contents is the fully qualified name of the implementation of JsonParser in that library. Then your getJsonParser method would look like:
public JsonParser getJsonParser() {
return ServiceLoader.load(JsonParser.class).iterator().next();
}
IMO this approach is unnecessarily more complex than the first.
I am trying to integrate Jackson on my java code to convert object to Json and back. My project is a web application developed in for Tomcat7 and Java7. I just downloaded the last version (2.6.0) jars of Jackson and was trying to do convert an object to json.
String outJson ="";
myobject p = new myobject ();
ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
try {
outJson = mapper.writeValueAsString(p);
} catch (Exception e) {
out.println(e.toString());
}
When I run this, I get an exception like this:
com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException)
I have done the oposite way, converting from json to the object and the result was ok.
After some research I found some references to posible dependency problem, but I can not find what I am missing. I have included the following jars, obtained from Maven repository:
jackson-annotations-2.6.0.jar
jackson-core-2.6.0.jar
jackson-databind-2.6.0.jar
jackson-dataformat-smile-2.6.0.jar
jackson-jaxrs-json-provider-2.6.0.jar
jackson-module-jaxb-annotations-2.6.0.jar
Any ideas of what could be the problem?
As said in the comments the problem was that I was not initializing correctly the object. As there was no data, I got the NullPointerException.
Currently I'm using doxc4j version 3.2.1
The default argument for the method setHyperlinkStyle() is "Hyperlink".
So basically it would look like this in my code:
XHTMLImporter.setHyperlinkStyle("Hyperlink");
Can someone explain why I got error: Cannot make a static reference to the non-static method setHyperlinkStyle(String) from the type XHTMLImporter
While it is working fine when using some previous version.
And the other thing you can do, since you say that XHTMLImporter is an interface is that you can instantiate an anonymous class that implements the interface, and then call the hyperlink style from there. I would read the documentation for the new version of your library though. it sounds like they changed their API, and just naïvely trying to make stuff work could lead you down rabbitholes of stuff not working.
This is an example extracted of project samples folder in github.
XHTMLImporter xHTMLImporter= null;
Class<?> xhtmlImporterClass = null;
try {
xhtmlImporterClass = Class.forName("org.docx4j.convert.in.xhtml.XHTMLImporterImpl");
Constructor<?> ctor = xhtmlImporterClass.getConstructor(WordprocessingMLPackage.class);
xHTMLImporter = (XHTMLImporter) ctor.newInstance(pkg);
} catch (Exception e) {
log.error("docx4j-XHTMLImport jar not found. Please add this to your classpath.");
log.error(e.getMessage(), e);
return xhtmlError(sdtParent, docContainer, docfrag, "Missing XHTML Handler!");
}
This link found uses of XHTMLImporter, you can found more examples.
https://github.com/plutext/docx4j/search?utf8=%E2%9C%93&q=xhtmlimporter
If you can't use XHTMLImportImporterImpl try to add this dependency
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-ImportXHTML</artifactId>
<version>3.2.1</version>
</dependency>
You will need to create an instance of XHTMLImporter, instead of trying to use a method in a static context.
XHTMLImporter xi = new XHTMLImporter();
xi.setHyperlinkStyle("Hyperlink");
and use xi where you need it
I'm trying to query the annotations from a class using this code:
for (final Annotation annotation : annotations) System.out.println(annotation);
final JsonSchema[] schemas = clazz.getAnnotationsByType(JsonSchema.class);
if (schemas.length == 0) {
throw new IllegalArgumentException("No JsonSchema annotation found.");
}
If I arrive here via a unit test I get past the schemas.length test. If I do so via a Maven plugin which passes the URL of a class into URLClassLoader().loadClass() then it throws IllegalArgumentException. However, it also prints out:
#mypackage.JsonSchema()
i.e. The annotation appears to be there if I loop through the results of getAnnotations() but isn't found by getAnnotationsByType. What could be causing this?
Edit: If I try looping through and comparing the canonical names then casting to JsonSchema it won't let me as it appears to be a com.sun.proxy which is not an instanceof JsonSchema.
Edit: It's because they're in different class loaders, I'm sure. Quite how to fix that...
Got it.
I was passing an array of URLs for classes to load to new URLClassLoader(). By adding a second parameter of Thread.currentThread().getContextClassLoader() to the constructor it seems to load them into the same ClassLoader and everything then works as expected.