I have already use JAXB successfully to unmarshal certain xml file but I have another case that is more complex. Basically my xml file looks like these:
<BCLCurrenciesInflation>
<currenciesInflation>
<currency>
<curencyName>Yen</curencyName>
<countryName>Japan</countryName>
<issuingDate>1900-01-01</issuingDate>
<expirationDate></expirationDate>
<inflation>
<year>1900</year>
<percentage>16</percentage>
</inflation>
<inflation>
<year>1901</year>
<percentage>17</percentage>
</inflation>
</currency>
<currency>
<curencyName>Dolar</curencyName>
<countryName>USA</countryName>
<issuingDate>1900-01-01</issuingDate>
<expirationDate></expirationDate>
<inflation>
<year>1902</year>
<percentage>18</percentage>
</inflation>
<inflation>
<year>1903</year>
<percentage>19</percentage>
</inflation>
</currency>
</currenciesInflation>
so is basically a HashMap<String,BCLCurrency> and BCLCurrency looks like this:
public class BCLCurrency
{
#XmlElement(name = "currencyName")
public String name;
#XmlElement(name = "countryName")
public String country;
#XmlElement(name = "issuingDate")
public String issuingDate;
#XmlElement(name = "expirationDate")
public String expirationDate;
#XmlElement(name = "inflation")
public Map<String,float> inflationMap;
}
I was thinking about having two adapters, the second will be called from the first adapter but I don't feel comfortable with that solution.
Any ideas of how to pull this off?
PD: Funny story I cannot say hello at the beginning of the post, the system keeps suppressing it!
You can create/use a generic adaptor for map < K,V > instead of creating two adaptors.
Related
So I have recently migrated to v6 and I will try to simplify my question
I have the following class
#AllArgsConstructor
public class Songs {
String title;
List<String> genres;
}
In my scenario I want to have something like:
Then The results are as follows:
|title |genre |
|happy song |romance, happy|
And the implementation should be something like:
#Then("Then The results are as follows:")
public void theResultsAreAsFollows(Songs song) {
//Some code here
}
I have the default transformer
#DefaultParameterTransformer
#DefaultDataTableEntryTransformer(replaceWithEmptyString = "[blank]")
#DefaultDataTableCellTransformer
public Object transformer(Object fromValue, Type toValueType) {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType));
}
My current issue is that I get the following error: Cannot construct instance of java.util.ArrayList (although at least one Creator exists)
How can I tell cucumber to interpret specific cells as lists? but keeping all in the same step not splitting apart? Or better how can I send an object in a steps containing different variable types such as List, HashSet, etc.
If I do a change and replace the list with a String everything is working as expected
#M.P.Korstanje thank you for your idea. If anyone is trying to find a solution for this here is the way I did it as per suggestions received. Inspected to see the type fromValue has and and updated the transform method into something like:
if (fromValue instanceof LinkedHashMap) {
Map<String, Object> map = (LinkedHashMap<String, Object>) fromValue;
Set<String> keys = map.keySet();
for (String key : keys) {
if (key.equals("genres")) {
List<String> genres = Arrays.asList(map.get(key).toString().split(",", -1));
map.put("genres", genres);
}
return objectMapper.convertValue(map, objectMapper.constructType(toValueType));
}
}
It is somehow quite specific but could not find a better solution :)
I recently started working on a code which contains some JAXB serializable/deserializable classes. One of the classes has a few lists in it and I wanted to add a new list to it. The lists were initially declared as ArrayList. Similarly, the get methods were also returning ArrayList. I changed all of them to List and added the new list as well as List. But after that, I was not able to unmarshal the xml for this object into a JAVA object. When I change the fields back to ArrayList without any other change, the unmarshalling works fine. I have also tried to attach the DefaultValidationEventHandler to the Unmarshaller but it doesn't spit out any error while unmarshalling. Below is how the class looks like with class and variable names change
#XmlRootElement(name = "commandSet")
public class CommandSet {
private final ArrayList<Command> xCommands;
private final ArrayList<Command> yCommands;
#Override
#XmlElementWrapper(name = "xCommands")
#XmlElement(name = "xCommand", type = Command.class)
public ArrayList<Command> getXCommands() {
return this.xCommands;
}
#Override
#XmlElementWrapper(name = "yCommands")
#XmlElement(name = "yCommand", type = Command.class)
public ArrayList<Command> getYCommands() {
return this.yCommands;
}
}
When xCommands and yCommands are declared as List and the getters also return List, the unmarhsalling doesn't work.
In all the examples that I have found for unmarshalling lists, people have used List<> instead of ArrayList<>. Any ideas why is it not working for me with List<>?
Things I Noticed About Your Code
There are a couple of weird things I notice about your code that may or may not factor into your problem. At the very least I suspect the model you are experiencing the problem with is different from the model you posted in your question.
You have the fields marked final, but never initialize them.
You annotated both of the get methods with #Override but since CommandSet doesn't inherit from anything (other than Object), you aren't overriding anything.
Complete Working Example
Java Model
CommandSet
In this version of the CommandSet class I have made one of the properties type ArrayList and the other of type List to demonstrate that they both work. I have also removed the weird things about your code mentioned above.
import java.util.*;
import javax.xml.bind.annotation.*;
#XmlRootElement
public class CommandSet {
private final ArrayList<Command> xCommands;
private final List<Command> yCommands;
public CommandSet() {
xCommands = new ArrayList<Command>();
yCommands = new ArrayList<Command>();
}
#XmlElementWrapper(name = "xCommands")
#XmlElement(name = "xCommand")
public ArrayList<Command> getXCommands() {
return this.xCommands;
}
#XmlElementWrapper(name = "yCommands")
#XmlElement(name = "yCommand")
public List<Command> getYCommands() {
return this.yCommands;
}
}
Command
public class Command {
}
Demo Code
Demo
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(CommandSet.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("input.xml");
CommandSet commandSet = (CommandSet) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(commandSet, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<commandSet>
<xCommands>
<xCommand/>
<xCommand/>
</xCommands>
<yCommands>
<yCommand/>
<yCommand/>
</yCommands>
</commandSet>
class GroovyHello {
public String execute() {
println("Test String is " + TEST)
}
private static final String TEST = "Test"
}
Output for the above snippet in Groovy V.1.6.3 is
Test String is Test
Output for the above snippet in Groovy V.1.8.6 is
Test String is null
The above snippet prints the string successfully if I modify the declaration to have either static (private static String TEST = "Test") or final (private final String TEST = "Test"), but not both.
My theory that since object Static and Private then you don't have access to it as it is a separate object. However if it is just private then your method is part of the object and it has access to it. If it is just static then you have access to the field - the field is public by default.
We noticed this happening when we had Groovy++ in the runtime classpath from other transitive dependencies. If that's the case, you might look at that.
I have a cxf JAX-RS service which looks something like the one below. When I submit a request with requested type "application/xml" I would expect that cxf automatically converts my return value into xml. This works for the method getData, but not for the other 2 methods. The other 2 methods return a simple String representation of the return value such as 2.0 or true. How do I get cxf to return a XML document for all 3 methods?
#WebService
#Consumes("application/xml")
#Produces("application/xml")
public interface MyServiceInterface {
final static String VERSION = "2.0";
#WebMethod
#GET
#Path("/version")
String getVersion();
#WebMethod
#GET
#Path("/data/{user}")
Data[] getData(#PathParam("user") String username) throws IOException;
#WebMethod
#GET
#Path("/user/{user}")
boolean doesUserExist(#PathParam("user") String username);
}
The issue is that neither String nor boolean has a natural representation as an XML document; XML requires an outer element, and neither CXF nor JAXB (the XML binding layer) knows what it should be.
The simplest method is to return the basic type inside a little JAXB-annotated wrapper:
#XmlRootElement
public class Version {
#XmlValue
public String version;
}
#XmlRootElement
public class UserExists {
#XmlValue
public boolean exists;
}
#WebService
#Consumes("application/xml")
#Produces("application/xml")
public interface MyServiceInterface {
final static String VERSION = "2.0";
#WebMethod
#GET
#Path("/version")
// TYPE CHANGED BELOW!
Version getVersion();
#WebMethod
#GET
#Path("/data/{user}")
Data[] getData(#PathParam("user") String username) throws IOException;
#WebMethod
#GET
#Path("/user/{user}")
// TYPE CHANGED BELOW!
UserExists doesUserExist(#PathParam("user") String username);
}
The other way of doing this would be to register providers that know how to convert strings and booleans into XML, but that's messy and affects your whole application in unexpected ways and you really shouldn't do that for simple types, OK?
I would like to make a macro that would essentially expand this:
#WithBasicConstructor
class Person {
private String name
private String address
}
into this:
class Person {
private String name
private String address
Person(String name, String address) {
this.name = name
this.address = address
}
}
I've been reading through the code for #Immutable to get a feel for how it is done. Has anyone used the new AstBuilder?
Any ideas how to implement this? Is there a preferred option between AstBuilder for string/code/spec ?
You could use (or copy) #groovy.transform.TupleConstructor from groovy 1.8.
Regarding preferences... I like the buildFromSpec, it leads to fewer surprises.
But I'd suggest you try the buildFromCode, test its limitations and quirks, play a little with all of them.