Use XSD schema to describe Java Properties generated by 'storeToXML ' - java

I use Properties#storeToXML to convert java.util.Properties to XML format. However, by default it generates XML with DTD schema for it:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
...
</properties>
Is it possible to use XSD schema for it instead? How can I reconfigure it?

Using the default classes, there seems to be no way of changing a doctype declaration to a XSD-based approach.
But there seems to be a plugin way of interventing into the XML storing behavior (at least in Java 8): The method Properties.storeToXml internally delegates to a loaded XmlPropertiesProvider (from package sun.util.spi).
This properties provider is either loaded by inspecting the system property "sun.util.spi.XmlPropertiesProvider" or (if not found) by loading it with the service loader mechanism.
With this approach you can implement a XmlPropertiesProvider yourself (it's an abstract class with the methods load and store) and do those XML parts in your own way.
Since at least May, 2016, the Properties class uses jdk.internal.util.xml.PropertiesDefaultHandler and the following hard-coded object instantiation to both store and load XML:
PropertiesDefaultHandler handler = new PropertiesDefaultHandler();
This means the following code will no longer work to set the default handler for XML-based properties:
System.setProperty(
"sun.util.spi.XmlPropertiesProvider",
XmlPropertiesTransformer.class.getCanonicalName()
);
There does not appear to be a way to introduce a different handler because the PropertiesDefaultHandler class does not permit injection of custom handlers.

Related

Changing single parameters in XML file wrapped as Java Object

I am getting a config.xml file via a REST API which has a specific structure. I am adapting this config.xml via Java and pushing it again via PUT command to the REST endpoint to update it.
This XML structure contains the same amount of properties (let's say 'name' and 'description') but might be enhanced by some more properties (e.g. 'category'), which I am not aware of.
<config>
<name>myName</name>
<description>myDescription<description>
<category>myCategory<category>
</config>
My goal is to adapt this config file via Java Code while wrapping it into an Object. So I built a Class 'Config' containing 'String name' and 'String description'.
I can easily parse the config.xml to my Config object with JAXB and adapt name and description, but when marshalling it to XML the category would be missing, although it was returned by the REST API. Is there a way (maybe ValueChangeListener?) to adapt only the changed values in an existing xml file?
public class Config { String name; String description; }
So I don't event want to be able to change 'category' at all, I just don't want to lose the data.
Info: In my scenario the Config class is very complex and has alot of subclasses (it's a representing a Jenkins Job). So the example above is very simplified.
I got the idea to create a second config file, only having the changed parameters. Afterwards merging the to config files. But I had no idea how to be aware what exactly has changed and how to implement it.
Example:
I want to change description to "newDescription", so my expected XML would be:
<config>
<name>myName</name>
<description>newDescription<description>
<category>myCategory<category>
</config>
unfortuntately it is:
<config>
<name>myName</name>
<description>newDescription<description>
</config>
Means category parameter is lost, as I am not aware of it and therefore didnt add it to the Config class. Summarized, there might be parameters in the XML file which I am not aware, which I also do not want to change - but don't want to lose when pushing an updated config.

Configuring global list of allowed classes for serialization

I am using Inifinispan v12.1 with String Boot v2.5.2 via org.infinispan:infinispan-spring-boot-starter-embedded. In our application we are using custom classes which we would like to cache (very common case), however it turned out that starting from v10 these classes need to be listed in "allow list".
We are using infinispan.xml configuration passed via infinispan.embedded.config-xml property as advised by sample project.
Question: How is it possible to configure allow list globally for all caches by the means of XML configuration file?
I have considered the following options:
System property infinispan.deserialization.allowlist.regexps (from ClassAllowList) – not good choice as configuration will be spread between XML file and e.g. some other place. More over if the property is renamed in future Infinispan versions one would notice it only when application is run.
Defining the <cache-container><serialization><allow-list> as to documentation is not good option because will result several identical per-cache XML configuration blocks.
The corresponding Java Config for Spring Boot application would be:
#org.springframework.context.annotation.Configuration
public class InfinispanConfiguration {
#Bean
public InfinispanGlobalConfigurationCustomizer globalCustomizer() {
return builder -> builder.allowList().addRegexp("^org\\.mycompany\\.");
}
}
P.S. Javadoc in GlobalConfiguration assumes that there is <default> XML section the configuration can be read from, but in fact XML does not support it anymore.
P.P.S. Arguably the dots in the packages should be escaped in SpringEmbeddedModule and start with ^ because ClassAllowList uses Matcher#find() (boolean regexMatch = compiled.stream().anyMatch(p -> p.matcher(className).find());):
serializationAllowList.addRegexps("^java\\.util\\..*", "^org\\.springframework\\..*");

JAXP: How to dynamically resolve a Schema during XML parsing?

Imagine a xml file which refers to a schema using noNamespaceSchemaLocation.
I'd like to resolve the value defined in noNamespaceSchemaLocation dynamically using some kind of resolving technique (like ResourceResolver for resolving schema includes) during parsing (default values in the schema have to be considered)
Is there a way to do this?
I would guess that when you call Validator.setResourceResolver(), the LSResourceResolver you supply is used for this purpose (it is in the Saxon implementation of the JAXP interface, but you would need to run a test to check that it's also true of the Xerces implementation).

How should I use Stax2 Validation API against a W3 Schema

I am using com.ctc.wstx.stax.WstxOutputFactory to generate XML.
I am running wstx-asl-3.2.4
I need to start validating the generated XML against a W3 Schema.
When I create an instance of org.codehaus.stax2.validation.XMLValidationSchemaFactory like this
private final static XMLValidationSchemaFactory xsdFact=
XMLValidationSchemaFactory.newInstance(XMLValidationSchema.SCHEMA_ID_W3C_SCHEMA);
I get the error
javax.xml.stream.FactoryConfigurationError: No XMLValidationSchemaFactory implementation class specified or accessible (via system property 'org.codehaus.stax2.validation.XMLValidationSchemaFactory.w3c', or service definition under 'META-INF/services/org.codehaus.stax2.validation.XMLValidationSchemaFactory.w3c')
at org.codehaus.stax2.validation.XMLValidationSchemaFactory.newInstance(XMLValidationSchemaFactory.java:208)
at org.codehaus.stax2.validation.XMLValidationSchemaFactory.newInstance(XMLValidationSchemaFactory.java:98)
I can see that woodstox is bundled with a DTD parser only.
I found this article
which contains the unhelpful instruction
Get an instance of XMLValidationSchemaFactory that knows how to parse schemas of the type you need (RelaxNG == rng for this example).
I have been looking at the Sun Multi-Schema XML Validator which is supposed to contain the bits necessary to bolt on to the XMLSchemaValidation factory.
It looks like I might be able to use com.sun.msv.reader.xmlschema.XMLSchemaReader
to write my own instance of XMLValidationSchemaFactory and get it to work this way.
My question is; do I really have to do this, or is there a pre-existing w3c schema factory that I have failed to find?
Perhaps it would be simpler just to validate the XML after I have generated it.
What are the views on this ?
I've upgraded to Woodstox 4.0.8, W3CSchemaFactory comes bundled and its all good.

Generate Spring bean definition from a Java object

Let's suggest that I have a bean defined in Spring:
<bean id="neatBean" class="com..." abstract="true">...</bean>
Then we have many clients, each of which have slightly different configuration for their 'neatBean'. The old way we would do it was to have a new file for each client (e.g., clientX_NeatFeature.xml) that contained a bunch of beans for this client (these are hand-edited and part of the code base):
<bean id="clientXNeatBean" parent="neatBean">
<property id="whatever" value="something"/>
</bean>
Now, I want to have a UI where we can edit and redefine a client's neatBean on the fly.
My question is: given a neatBean, and a UI that can 'override' properties of this bean, what would be a straightforward way to serialize this to an XML file as we do [manually] today?
For example, if the user set property whatever to be "17" for client Y, I'd want to generate:
<bean id="clientYNeatBean" parent="neatBean">
<property id="whatever" value="17"/>
</bean>
Note that moving this configuration to a different format (e.g., database, other-schema'd-xml) is an option, but not really an answer to the question at hand.
You can download the Spring-beans 2.5 xsd from here and run xjc on it to generate the Java classes with JAXB bindings. Then you can create the Spring-beans object hierarchy on runtime (and manipulate it as you wish) and then serialize it to an XML string using the JAXB Marshaller as shown in Pablojim's answer.
I'd use Jax-b to do this. You'de create a bean object with a list of property objects inside.
#XmlRootElement(name = "bean")
#XmlAccessorType(XmlAccessType.FIELD)
public class Bean {
#XmlAttribute
private String id;
#XmlAttribute
private String parent;
#XmlElement(name="property")
private List<BeanProperty> properties
Then You'd need to also add annotations to BeanProperty. Then when you have a populated object simply marshal it to xml using jaxb:
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal( myBean, System.out );
For full code examples see: http://java.sun.com/webservices/docs/2.0/tutorial/doc/JAXBUsing.html
Alternatively you could use Groovy - you can drop it in place and creating this xml would be very simple... : http://www.ibm.com/developerworks/java/library/j-pg05199/index.html
If you want a simple to implement, no work solution, you can look at the IDE support provided in IntelliJ and Eclipse (The Spring Tool Suite).
They parse all the bean files (you can configure which set) and inspect the java code so it knows which classes there are, which properties are in those classes. Everywhere you can use Ctrl-Space to help with the options, etc...
I imagine you could setup 'projects' w/o Java code and only the spring config files in order to reduce the learning curve of front line personnel who must make these changes.
What you need is obviously a factory for your neatBeans.
In Spring, instead of declaring a bean, you can declare a FactoryBean whose role is to actually create and configure your final bean.
The NeatBeanFactoryBean could read a property file (or xml configuration) to determine how to configure the produced neatBeans, depending on some runtime parameter (the current clientID for example) or compile-time parameter (environment variable).
To add to the other two questions, I believe Spring already has a working model for bean definitions (see org.springframework.beans.factory.config.BeanDefinition); you could base your work on that.
I'd suggest using
<context:property-placeholder location="classpath*:clientX.properties"/>
and then in your bean def:
<bean id="${clientYNeatBeanId}" parent="neatBean">
<property id="whatever" value="${whateverValue}"/>
</bean>
Then for each client you can have a clientX.properties containing
whateverValue=17
whateverAnotherValue=SomeText
.properties files are easier to edit both manually, and programaticalyl via java.util.Properties store(..) / save(..) methods

Categories