XFire

Map entries not reconstructed on other side of WS call due to namespace mismatch

Details

  • Type: Bug Bug
  • Status: Open Open
  • Priority: Blocker Blocker
  • Resolution: Unresolved
  • Affects Version/s: 1.2.4
  • Fix Version/s: 1.2.7
  • Component/s: Aegis Module
  • Labels:
    None
  • Environment:
    Discovered on server running Jetty 5.1.10, though this appears to occur universally
  • Number of attachments :
    0

Description

I have a simple Map<String, String> as one of the bean properties of an object that is being sent across the wire. When this object is being written out on the client side, the EntryWriter used has a namespace of "services.c.b.a.com" (anonymised). This is more or less what I would expect from the generation; at least, it matches the QName for my map entries according to the map's Type (as it should from line 180).

When the parameter is read on the server side, flow correctly passes into MapType.readObject(). The object that this method is called on is identical to the serialising object on the server; specifically, it also has an entry type QName of "services.c.b.a.com". However, when the call goes out to reader.getNextElementReader() (line 61), the ElementReader that is returned inherits its name from the 'root' reader - and this is set to "presentation.c.b.a.com". As a result, the test on line 63 fails as the namespaces are different, and no map entries are ever read.

As a result my maps are always recreated empty on the other side of the WS call.

This seems to be an issue within the MapType - if the ElementReader on the write side is created to have the same namespace as the map's type, then surely this should be the same on the read side. Currently it seems that this will fail any time MapType.getKeyName() != ElementReader.root.getName().

I haven't attached any test cases as I'm not familiar with how the MessageReaders passed into MapType.readObject() are created, and when & why the above inequality occurs. I'll step through the debugger and try to come up with some tests, but I'm submitting the bug now in the hope that someone with more familiarity in that area will be able to quickly see what the root cause is.

Activity

Hide
Andrzej Doyle added a comment -

This may actually be caused by using a legacy version of Woodstox (2.0.6). I note that versions earlier than 3.0.3 are deemed as legacy and that XFire's dependancy guide has been updated accordingly. I'll ensure all my libraries are up to date and see if this issue persists.

Show
Andrzej Doyle added a comment - This may actually be caused by using a legacy version of Woodstox (2.0.6). I note that versions earlier than 3.0.3 are deemed as legacy and that XFire's dependancy guide has been updated accordingly. I'll ensure all my libraries are up to date and see if this issue persists.
Hide
Andrzej Doyle added a comment -

This problem still persists with the latest value of Woodstox. I've had a brief look through the code and it seems that the 'root' reader is created in XFireServletController.invoke() (line 294), but I can't work out at what stage its name is determined.

Show
Andrzej Doyle added a comment - This problem still persists with the latest value of Woodstox. I've had a brief look through the code and it seems that the 'root' reader is created in XFireServletController.invoke() (line 294), but I can't work out at what stage its name is determined.
Hide
Dan Diephouse added a comment -

Thanks. That information should help us track down the problem. Any chance you can create a sample which recreates this problem?

Show
Dan Diephouse added a comment - Thanks. That information should help us track down the problem. Any chance you can create a sample which recreates this problem?
Hide
Andrzej Doyle added a comment -

I'm working on creating a sample, but in the process of doing so I think my analysis was incorrect. I initially assumed that 'root' referred to something like the document element, but now I get the feeling it means something more like 'lowest-level'; in any event, modifying the MapTypeTest JUnit test case suggests that the blame doesn't lie where I originally thought.

I've had more of a look at the writing side as a result and it seems there's a major discrepancy there... despite the MessageWriters that create the map, entry and key element having the "

Show
Andrzej Doyle added a comment - I'm working on creating a sample, but in the process of doing so I think my analysis was incorrect. I initially assumed that 'root' referred to something like the document element, but now I get the feeling it means something more like 'lowest-level'; in any event, modifying the MapTypeTest JUnit test case suggests that the blame doesn't lie where I originally thought. I've had more of a look at the writing side as a result and it seems there's a major discrepancy there... despite the MessageWriters that create the map, entry and key element having the "
Hide
Andrzej Doyle added a comment -

(Oops, there's apparently a submit short cut I hit by mistake. Continuing

...having "services.c.b.a.com" as their namespace, according to java interrogation, the actual XML document produced has "presentation.c.b.a.com" as the output, which would explain why there's a mismatch. With this new information, it seems that the reading side is doing completely the right thing - and while the write side tries to do the right thing, it's not happening somehow.

FYI, the actual root writer in this situation is an instance of org.codehaus.xfire.util.stax.W3CDOMStreamWriter.

I'll continue the investigation and see if I can produce some failing test cases.

Show
Andrzej Doyle added a comment - (Oops, there's apparently a submit short cut I hit by mistake. Continuing ...having "services.c.b.a.com" as their namespace, according to java interrogation, the actual XML document produced has "presentation.c.b.a.com" as the output, which would explain why there's a mismatch. With this new information, it seems that the reading side is doing completely the right thing - and while the write side tries to do the right thing, it's not happening somehow. FYI, the actual root writer in this situation is an instance of org.codehaus.xfire.util.stax.W3CDOMStreamWriter. I'll continue the investigation and see if I can produce some failing test cases.
Hide
Dan Diephouse added a comment -

A failing test case would be awesome. I can probably get out a fix very easily if you have one.

Show
Dan Diephouse added a comment - A failing test case would be awesome. I can probably get out a fix very easily if you have one.
Hide
Joost den Boer added a comment -

According to the description, this problem always exists for Maps.
I can confirm this is not the case. I use an object containing 2 Hashtable Maps which are correctly serialized/deserialized by XFire.
The one difference I see in our case compared to this example, is that we have our own Aegis binding files which define a custom namespace for the objects. Also, in the binding file I specify the map attribute as class java.util.Hashtable.
We cannot only successfully transfer Map<String,String>, but also Map<String,Object> and Map<String,List<ValueObject>>

Hope this helps in finding the real problem.

Show
Joost den Boer added a comment - According to the description, this problem always exists for Maps. I can confirm this is not the case. I use an object containing 2 Hashtable Maps which are correctly serialized/deserialized by XFire. The one difference I see in our case compared to this example, is that we have our own Aegis binding files which define a custom namespace for the objects. Also, in the binding file I specify the map attribute as class java.util.Hashtable. We cannot only successfully transfer Map<String,String>, but also Map<String,Object> and Map<String,List<ValueObject>> Hope this helps in finding the real problem.
Hide
bill graham added a comment -

After many struggles I've also been able to get Maps working with Java5/Generics. The workaround in the above example is to name your services namespace with the default namespace of the beans (or vice-versa, but I couldn't get that working). To follow the example above we have this:

service namespace -> services.c.b.a.com
bean namespace -> presentation.c.b.a.com

which is what causes the conflict when reading a map. I'm trying to read from the client and this happens regardless of what the namespaces are on my wsdl on the server. The default service namespace is the inverted package structure of the service interface. Similarly the default for the beans is the inverted package name of the bean location. The two need to match for maps to be handled. I'm not sure if this is a bug with MapType or not, but this behavior doesn't surface itself for Collections so it seems like MapType has inconsistent behavior.

The workaround (using annotations) was to add this to the service interface used by my client:

@WebService(
serviceName = "SomeService ",
endpointInterface = "com.a.b.c.services.SomeService ",
targetNamespace = "presentation.c.b.a.com"
)
public interface SomeService {
public SomeObjectWithAMap getSomeObject(RequestObject request);
}

Dan, in lieu of a code sample I think this should help to reproduce the issue. By changing the targetNamespace above you should see the problem.

Show
bill graham added a comment - After many struggles I've also been able to get Maps working with Java5/Generics. The workaround in the above example is to name your services namespace with the default namespace of the beans (or vice-versa, but I couldn't get that working). To follow the example above we have this: service namespace -> services.c.b.a.com bean namespace -> presentation.c.b.a.com which is what causes the conflict when reading a map. I'm trying to read from the client and this happens regardless of what the namespaces are on my wsdl on the server. The default service namespace is the inverted package structure of the service interface. Similarly the default for the beans is the inverted package name of the bean location. The two need to match for maps to be handled. I'm not sure if this is a bug with MapType or not, but this behavior doesn't surface itself for Collections so it seems like MapType has inconsistent behavior. The workaround (using annotations) was to add this to the service interface used by my client: @WebService( serviceName = "SomeService ", endpointInterface = "com.a.b.c.services.SomeService ", targetNamespace = "presentation.c.b.a.com" ) public interface SomeService { public SomeObjectWithAMap getSomeObject(RequestObject request); } Dan, in lieu of a code sample I think this should help to reproduce the issue. By changing the targetNamespace above you should see the problem.
Hide
Piers Geyman added a comment -

Is any work being done on this issue?
We have just created a web services application that passes maps around and are having big problems with this.

Show
Piers Geyman added a comment - Is any work being done on this issue? We have just created a web services application that passes maps around and are having big problems with this.

People

Vote (10)
Watch (9)

Dates

  • Created:
    Updated: