0

I'm building a fitness tracker application which allows a user to track their workouts. A workout is comprised of a list of movements. The abstract Movement class is extended by several subtypes of movement.

Abstract class:

@XmlSeeAlso({BodyweightMovementDTO.class, CalorieMovementDTO.class,
             DistanceMovementDTO.class, WeightedMovementDTO.class})
public abstract class Movement {
  public abstract MovementType getType();
  public abstract void setType(final MovementType type);
}

Extended by:

@XmlRootElement(name = "weightedMovement")
public class WeightedMovementDTO extends Movement {
  private MovementType type;
  private Integer weight;
  private Integer reps;

  public WeightedMovementDTO(final MovementType type, final Integer weight, final Integer reps) {
    this.type = type;
    this.weight = weight;
    this.reps = reps;
  }

  //Getters and Setters

 }

And also extend by:

@XmlRootElement(name = "distanceMovement")
public class DistanceMovementDTO extends Movement {
  private MovementType type;
  private Integer distance;

  public DistanceMovementDTO(final MovementType type, final Integer distance) {
    this.type = type;
    this.distance = distance;
  }

  //Getters and setters
}

And two more similar classes.

The resource method that allows a PUT of a workout or WorkoutResultDTO is as follows:

  @PUT
  @Path("{user}/today")
  @Consumes({ MediaType.APPLICATION_JSON })
  public Response recordResult(@PathParam(value = "user") final String user, 
                               final WorkoutResultDTO result) {
    WorkoutController.recordResult(user, result);
    return Response.ok().build();
  }

The WorkoutResultDTO is the object which I assume is causing the problem as it has an ArrayList of the abstract Movement object.

@XmlRootElement(name = "workout")
public class WorkoutResultDTO implements Result {
  private int id = 0;
  private OcsidDate date = new OcsidDate(LocalDate.now());
  private Scale scale = null;
  private WorkoutType workoutType = null;
  private List<Movement> wod = new ArrayList<>();
  private boolean complete = false;
  private double time = 0.0;
  private int reps = 0;

  public WorkoutResultDTO() {}

  public WorkoutResultDTO(final int id) {
    this.id = id;
  }

  //Getters and Setters

}

The when I do a PUT to my endpoint using postman I get the following error returned:

Can not construct instance of ninja.ocsid.crossfit.dto.movement.abstracts.Movement, 
problem: abstract types either need to be mapped to concrete types, 
have custom deserializer, or be instantiated with 
additional type information  at [Source:org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@41d13e9b; 
line: 16, column: 9] (through reference chain: 
ninja.ocsid.crossfit.dto.result.WorkoutResultDTO["movements"])

I was lead to believe that adding the line:

@XmlSeeAlso({BodyweightMovementDTO.class, CalorieMovementDTO.class,
                 DistanceMovementDTO.class, WeightedMovementDTO.class})

would solve this problem as that annotation would give enough information as to how the abstract class can be deserialised to one of the concrete types, but this does not seem to be the case. Am I missing some other configuration or some custom class that is need to do this? I've been trying to solve this for two days now which much googling, but to no avail. Any input would be welcome. Thanks!

EDIT: Details of the PUT request attached in an image.

Details of PUT request

Drew
  • 57
  • 1
  • 7
  • as of my knowledge, if your PUT request is an XML, you have to specify the concrete type of `Movement`, by adding `xsi:type="YourMovementConcreteType"` – Mustapha Belmokhtar Jul 28 '18 at 17:43
  • hi! Thanks for your comment, can you elaborate on this? where do I put that string, can you give an example? – Drew Jul 28 '18 at 19:24
  • I would like to see your put requrst first – Mustapha Belmokhtar Jul 28 '18 at 19:33
  • I use postman to do the PUT, but I'm using JSON, not XML. I've updated the question to include an image. If you need more details, please let me know! Thanks! – Drew Jul 29 '18 at 09:34
  • If you're using JSON, how are are the Xml annotation relevant? What is the JSON parser you're actually using? – JB Nizet Jul 29 '18 at 09:40
  • They allow me to set what the property names are in the JSON that's returned. For example, WorkoutResultDTO can just be called "workout" in the JSON. I'm using these dependencies, which I believe are responsible for the JSON parsing: org.glassfish.jersey.containers jersey-container-servlet 2.23.2 org.glassfish.jersey.media jersey-media-json-jackson 2.9 – Drew Jul 29 '18 at 11:05

0 Answers0