Jibx: Integrate base class output into extending class output - java

I have this class model:
abstract class A {
int a;
}
class B extends A {
int b;
}
class C extends B {
int c;
}
And I'd like to get jibx to output this XML:
<B b=1 a=0>
<children>
<C c=2 b=1 a=0/>
</children>
</B>
I have this binding xml:
<binding>
<mapping class="A" abstract="true">
<value name="a" field="a" style="attribute" usage="optional"/>
<collection field="children" type="java.util.ArrayList"/>
</mapping>
<mapping name="B" class="B" extends="A">
<value name="b" field="b" style="attribute" usage="optional"/>
<structure map-as="A"/>
</mapping>
<mapping name="C" class="C" extends="B">
<value name="c" field="c" style="attribute" usage="optional"/>
<structure map-as="B"/>
</mapping>
</binding>
However I keep getting artifacts like this:
<C c=2>
<B b=1 a=0>
<children>
...
</children>
</B>
</C>
As temporary solution I've changed my inheritance structure to have AbstractB and B extends AbstractB and C extends AbstractB, but it really annoys me to have to redesign my class because of jibx.
Anyone knows how to solve this?
Edit:
As a bonus question - how do you use code/decode java.util.Map with Jibx? I know it can't be done natively (would be glad to be disproved!) but what would you do to code Map (no strings). Please note we're not using jibx-extras.jar, so solutions should not rely on it.

Actually IMHO it feels kind of normal to get C as parent (in XML sense) of B, because C contains the information of B (from wich it inherits) and its own information aside, but B doesn't know about those C-specific information right ?
To make it clearer: it B is Bird and C is Chicken. Chicken is a Bird, so C inherits form B, OK. But in XML format, would store :
<Bird color="brown">
<Chicken label="Kentucky-fried" />
</Bird>
or
<Chicken label="Kentucky-fried"> <!-- chicken-specific information -->
<Bird color="brown" /> <!-- "birdy" part of the chicken -->
</Chicken>
?
So on the model point of view, it seems logical to me...
And I didn't find a way of achieving the opposite in the binding tutorial, sorry.

Related

obfuscating with allatori obfuscates too much

I have the following config.xml file
<config>
<input>
<jar in="FVCellsPlugin-3.3.1-jcg.jar" out="obf-FVCellsPlugin-3.3.1-jcg.jar"/>
</input>
<keep-names>
<class template="class io.github.freakyville.fvcells.main.Main"/>
<class template="class regex:(?!io\.github\.freakyville).*\..*">
<field template="*"/>
<field template="static *"/>
<field template="public static *"/>
<method template="private+ *(**)"/>
<method template="private+ static *(**)"/>
</class>
<class template="private+ class regex:io\.github\.freakyville\.utilsupdated\..*"/>
</keep-names>
<property name="log-file" value="log.xml"/>
<property name="line-numbers" value="keep"/>
</config>
So I tried a few things without it working, all my code that i want obfuscated is in the package(or sub packages) io.github.freakyville(except io.github.freakyville.utilsupdated).
when the plugin is enabled I get an error java.lang.NoSuchMethodError: com.mongodb.client.model.geojson.c.iiiiiI(Ljava/lang/String;)Ljava/lang/String; which shows that it is obfuscating the class inside com.mongodb.client.model.geojson, When looking inside the jar I can see that it has obfuscated the geojson.c class https://gyazo.com/45c17157d5d7a213f14a9ecc2c12b4f6 which to me doesn't make sence as my regex (?!io\.github\.freakyville).*\..* should match that package/class path and then keep the package/class right?
Ah I figured it out, I missed the tag in the documentation(which ignores the classes matched in the obfuscating process). Adding my class templates to that and now it works

OWL java use same data property for two classes

I am working with OWL and I have defined 2 classes and they share a data propertie:
<Declaration>
<DataProperty IRI="#hasLastName" />
</Declaration>
<DataPropertyDomain>
<DataProperty IRI="#hasLastName" />
<Class IRI="#Class1" />
</DataPropertyDomain>
<DataPropertyDomain>
<DataProperty IRI="#hasLastName" />
<Class IRI="#Class2" />
</DataPropertyDomain>
In java I have created a project that starting from an owl file and an xml file it creates a form.
in my xml file I define the sections of the form in this way:
<section>
<iri>http://www.sample.com/myontology#class1</iri>
<infoList>
<info type="text" property="http://www.sample.com/myontology#hasLastName" required="true" />
<info type="text" property="http://www.sample.com/myontology#hasFirstName" required="true" />
<info type="text" property="http://www.sample.com/myontology#hasEmail" required="false" />
<info type="text" property="http://www.sample.com/myontology#hasPhone" required="false" />
</infoList>
</section>
<section>
<iri>http://www.sample.com/myontology#class2</iri>
<infoList>
<info type="text" property="http://www.sample.com/myontology#hasLastName" required="true" />
<info type="text" property="http://www.sample.com/myontology#hasUser" required="false" />
<info type="text" property="http://www.sample.com/myontology#hasRole" required="false" />
</infoList>
</section>
How can I access the different Last name Properties for class 1 and class 2?
I retrieve it by http://www.sample.com/myontology#hasLastName
There is something like http://www.sample.com/myontology#Class1#hasLastName ?
Sorry I am a very beginner with Ontology and it is not very clear to me
Assuming you have an ontology as follows:
Datatype: xsd:string
DataProperty: hasLastName
Domain:
Person,
Student
Range:
xsd:string
Class: Person
Class: Student
the following code will retrieve the 2 domains:
IRI lastNamePropertyIRI = IRI.create(ontologyIRI + "#hasLastName");
OWLDataProperty lastNameProperty = dataFactory.getOWLDataProperty(lastNamePropertyIRI);
List<OWLClassExpression> domainClasses =
ontology
.dataPropertyDomainAxioms(lastNameProperty)
.map(OWLDataPropertyDomainAxiom::getDomain)
.collect(Collectors.toList());
for (OWLClassExpression owlClass : domainClasses) {
logger.trace("Domain class = " + owlClass);
}
However, there are some other problems I am concerned with here which relates to the ontology rather than the code.
For the ontology I have given, whenever you specify that an individual john is linked to some surname via hasLastName, the ontology reasoner will infer that john is both a Person and a Student, i.e. the domain of hasLastName is the intersection of Person and Student. Clearly, this is not true for people in general. There are 2 possible solutions to this, depending on your needs:
(1) You can specify that the domain of hasLastName is Person or Student which will take the domain to be the union of Person and Student.
(2) The solution I prefer is to define Student as a subclass of Person and then to state that the domain of hasLastName is the single class Person.

JiBX Binding: Adding a value and attribute to a structure, from properties which are in the same java Object

As I am new to JiBX, I don't know if this is possible, but I feel like I am overlooking something. I am trying to find a way to bind two properties from one POJO, to the same structure in two different ways. One as the value of the structure, the second as an attribute of the same structure.
The example below shows what I intend to do.
Keep in mind that this binding will only have to work one way, from Java to XML. (The binding will be defined as <binding direction="output">)
A simplified version of the classes I am trying to map:
public Example(){
private objectToMap;
//Constructor, getters and setters go here
}
public ObjectToMap(){
private String randomProperty;
private String value = "a";
private Attribute;
//Constructor, getters and setters go here
}
public Attribute(){
private String attribute = "b";
//Constructor, getters and setters go here
}
The XML I want to generate has too look like this:
<Example>
<RandomProperty>randomValue</RandomProperty>
<ObjectToMapValue attribute="b">a</ObjectToMapValue>
</Example>
And this is where I get stuck:
<binding direction="output">
<mapping name="Example" class="com.example.pojo.Example">
<structure field="objectToMap" type="com.example.pojo.ObjectToMap">
<value name="RandomProperty" field="randomProperty">
<structure name="ObjectToMapValue" field="value"/>
<!-- But how to add the attribute? -->
</structure>
</mapping>
</binding>
Is it possible to make a JiBX binding do this?
Got it working, and as I thought, I was overlooking something. This is what solved it:
<binding direction="output">
<mapping name="Example" class="com.example.pojo.Example">
<structure field="objectToMap" type="com.example.pojo.ObjectToMap">
<value name="RandomProperty" field="randomProperty">
<structure name="ObjectToMapValue" field="value">
<structure field="Attribute"/>
<value style="text" field="value">
</structure>
</structure>
</mapping>
<mapping class="com.example.pojo.Attribute" abstract="true">
<value name="attribute" field="attribute" style="attribute">
</mapping>
</binding>

Unmarshalling list of objects using castor gives java.lang.IllegalArgumentException: object is not an instance of declaring class

I'm using castor 1.3.3-rc1 and I've been puzzled with this problem. Have read the manuals few times and I believe I've done everything right here, but I keep getting :
java.lang.IllegalArgumentException: object is not an instance of declaring class{File: [not available]; line: 4; column: 43}
when unmarshalling my xml.
These are my java classes:
public class ReportConfiguration {
private List<ColumnMapping> columnMappings;
// getters and setters omitted
}
public class ColumnMapping {
private int index;
private String label;
private String sumTotal;
// getters and setters omitted
}
This is my xml data file which will be unmarshalled into java classes above
<reportConfiguration>
<columnMappings>
<columnMapping index="0" label="Login"/>
<columnMapping index="1" label="Group"/>
<columnMapping index="2" label="Profit" sumTotal="yes"/>
</columnMappings>
</reportConfiguration>
And this is my castor mapping file
<mapping>
<class name="my.company.ReportConfiguration">
<map-to xml="reportConfiguration"/>
<field name="columnMappings" collection="arraylist" type="my.company.ColumnMapping">
<bind-xml name="columnMappings"/>
</field>
</class>
<class name="my.company.ColumnMapping">
<map-to xml="columnMapping"/>
<field name="index" type="integer" required="true">
<bind-xml name="index" node="attribute"/>
</field>
<field name="label" type="string" required="true">
<bind-xml name="label" node="attribute"/>
</field>
<field name="sumTotal" type="string">
<bind-xml name="sumTotal" node="attribute"/>
</field>
</class>
</mapping>
I used Spring OXM, created a org.springframework.oxm.castor.CastorMarshaller instance on my application context, and injected an Unmarshaller instance as dependency. When unmarshalling I just do something like this:
ReportConfiguration config = (ReportConfiguration) unmarshaller.unmarshall(new StreamSource(inputStream));
Can anyone spot what did I do wrong / how else I can debug this problem ?
Ah actually I found the answer. I need to supply container="false" attribute on the castor mapping :
<field name="columnMappings" collection="arraylist" type="my.company.ColumnMapping" container="false">
<bind-xml name="columnMappings"/>
</field>
This is what castor manual says:
container Indicates whether the field should be treated as a
container, i.e. only it's fields should be persisted, but not the
containing class itself. In this case, the container attribute should
be set to true (supported in Castor XML only).
I think the default is true -- in which case castor hopes to find multiple instance of <columnMapping> directly under <reportConfiguration>, not contained inside a <columnMappings>
A more helpful error message could be presented.

Mapping collection to XML in Castor

I'm trying to map a POJO to XML using Castor.
Let's say I have a Order that has a collection of Items... is there any way of achieving an xml like the following:
<order>
...order attributes
<items>
<item> ..item attributes </item>
<item> ..other item </item>
</items>
</order>
I could make something similar but without the <items> node. This wouldn't be a problem in other case but my XML must adhere to a strict XSD schema so I need to do it like that.
Thanks!
I though of a kind of "workaround" that would involve creating a new java object (that would be the node) that would only contain the list of items... can anyone think of a better approach? there's a 100 rep bounty open since now!
You can use the location attribute of the bind-xml lement
http://castor.codehaus.org/1.2/xml-mapping.html#6.-Location-attribute
Example from the docs:
<class name="Foo">
<field name="bar" type="Bar">
<bind-xml name="bar" location="abc"/>
</field>
</class>
Produces the following XML:
<foo>;
<abc>
<bar>...</bar>
</abc>
</foo>
The other answer doesn't use the collection attribute which I think is probably what you're ultimately needing.
Something like this might work when included in your mapping for the Order object:
<field name="items" type="item" collection="arraylist" >
<bind-xml name="items" node="element"/>
</field>

Categories