jersey
  1. jersey
  2. JERSEY-2041

JAX-RS: polymorphic PUT requests do not work with JSON

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Cannot Reproduce
    • Affects Version/s: 2.0
    • Fix Version/s: 2.5
    • Component/s: core
    • Labels:
      None
    • Environment:

      linux

      Description

      Consider the following code (setters and getter not shown):

      @XmlRootElement
      public class Container {
      
          private List<Item> items = new ArrayList<Item>();
      }
      
      @XmlSeeAlso(value = { ItemA.class, ItemB.class })
      public abstract class Item {
      
          private String name;
      }
      
      public class ItemA extends Item {
      
          private Integer value;
      }
      

      Serialization and deserialization works fine with XML. With JSON serialization works but deserialization fails because of "SAXParseException2: Unable to create an instance of test.Item".

      It seems in com.sun.xml.bind.v2.runtime.unmarshaller.XsiTypeLoader.parseXsiType the matching is done by calling att.getIndex(String uri, String localName) with values "http://www.w3.org/2001/XMLSchema-instance" and "type". The values which would match would be ("", "type").

      If during debugging the value of index returned by getIndex is corrected manually, everything works fine.

      I tested also with GF 4.0-b57 but there even the serialization doesn't work. It results in MessageBodyProviderNotFoundException.

        Activity

        Hide
        syvalta added a comment -

        Minimal example project attached. After compilation and deployment the issue can be easily reproduced:
        curl -X GET -H "Accept:application/json" http://localhost:8080/gf-polymorphic-rest-1.0-SNAPSHOT/rest/test/container/1 > data.json
        curl -X PUT -H "Accept:application/json" -H "Content-Type:application/json" -d @data.json http://localhost:8080/gf-polymorphic-rest-1.0-SNAPSHOT/rest/test/container/1
        --> HTTP Status 400 - Bad Request

        With XML works fine:
        curl -X GET -H "Accept:application/xml" http://localhost:8080/gf-polymorphic-rest-1.0-SNAPSHOT/rest/test/container/1 > data.xml
        curl -X PUT -H "Accept:application/xml" -H "Content-Type:application/xml" -d @data.xml http://localhost:8080/gf-polymorphic-rest-1.0-SNAPSHOT/rest/test/container/1

        Show
        syvalta added a comment - Minimal example project attached. After compilation and deployment the issue can be easily reproduced: curl -X GET -H "Accept:application/json" http://localhost:8080/gf-polymorphic-rest-1.0-SNAPSHOT/rest/test/container/1 > data.json curl -X PUT -H "Accept:application/json" -H "Content-Type:application/json" -d @data.json http://localhost:8080/gf-polymorphic-rest-1.0-SNAPSHOT/rest/test/container/1 --> HTTP Status 400 - Bad Request With XML works fine: curl -X GET -H "Accept:application/xml" http://localhost:8080/gf-polymorphic-rest-1.0-SNAPSHOT/rest/test/container/1 > data.xml curl -X PUT -H "Accept:application/xml" -H "Content-Type:application/xml" -d @data.xml http://localhost:8080/gf-polymorphic-rest-1.0-SNAPSHOT/rest/test/container/1
        Hide
        Michal Gajdos added a comment -

        You have wrong getter in your ItemB class. After fixing it it works as expected. You can, as well, configure the MOXy JSON provider a little more:

        @ApplicationPath("rest")
        public class ContainerApplication extends Application {
        
            @Override
            public Set<Class<?>> getClasses() {
                Set<Class<?>> classes = new HashSet<Class<?>>();
                classes.add(ContainerService.class);
                return classes;
            }
        
            @Override
            public Set<Object> getSingletons() {
                final Map<String, String> namespaces = new HashMap<String, String>() {{
                    put("http://www.w3.org/2001/XMLSchema-instance", "xsi");
                }};
        
                return new HashSet<Object>() {{
                    add(new MoxyJsonConfig()
                            .setNamespacePrefixMapper(namespaces)
                            // .setNamespaceSeparator(':')
                            // .setAttributePrefix("@")
                            .resolver());
                }};
            }
        }
        
        Show
        Michal Gajdos added a comment - You have wrong getter in your ItemB class. After fixing it it works as expected. You can, as well, configure the MOXy JSON provider a little more: @ApplicationPath( " rest " ) public class ContainerApplication extends Application { @Override public Set< Class <?>> getClasses() { Set< Class <?>> classes = new HashSet< Class <?>>(); classes.add(ContainerService.class); return classes; } @Override public Set< Object > getSingletons() { final Map< String , String > namespaces = new HashMap< String , String >() {{ put( "http: //www.w3.org/2001/XMLSchema-instance" , "xsi" ); }}; return new HashSet< Object >() {{ add( new MoxyJsonConfig() .setNamespacePrefixMapper(namespaces) // .setNamespaceSeparator(':') // .setAttributePrefix( "@" ) .resolver()); }}; } }
        Hide
        syvalta added a comment -

        Thanks Michal. Verified this is fixed in GF 4.0

        Show
        syvalta added a comment - Thanks Michal. Verified this is fixed in GF 4.0

          People

          • Assignee:
            Michal Gajdos
            Reporter:
            syvalta
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Time Tracking

              Estimated:
              Original Estimate - 30 minutes Original Estimate - 30 minutes
              30m
              Remaining:
              Remaining Estimate - 0 minutes
              0m
              Logged:
              Time Spent - 1 hour
              1h