0

We have a REST web service implemented with the Jersey framework that allows users to save configuration info from the UI. There is a GET (to get current config info) and a corresponding POST to save settings. That data is saved in a JSON file. The GET works perfectly, as does the POST exept for one value:

"modulation": 2,

No matter what this value is set to, when getting the data from the UI in the POST, it's always the default. Every other value is perfect.

This value used to be an enum and since everything in the file is saved as an int or String, I thought that might be confusing it. So I changed it to an int. That didn't help. On the bright side, it didn't make anything worse either.

Using good ol' Postman, I send a JSON structure with the POST:

{
    "customers": {
        "max": 20,
        "current": 2
    },
    "window": {
        "x": 10,
        "y": 10,
        "width": 20,
        "height": 20
    },
    "modulation": 2,    // always just the default, 1
    "pointsOfConsternation": 20
}

It gets automagically converted into an object that we use for configuration. All the values come across correctly except that pesky mode. Here is what the receiving method signature looks like:

@POST
@Consumes({MediaType.APPLICATION_JSON})
@Produces(MediaType.TEXT_PLAIN)
@Path("/config")
public String setConfiguration( ConsternationConfig config ) {
    ...
    // do magic
    ...
}

I've debugged the crap out of it to no avail. The mangling happens in code that I don't have any control over. It comes into the POST method mangled.

Any idea on what might be going on?

UPDATE Per @Aleh Maksimovich, here is the source for ConsternationConfig:

@XmlRootElement
public class ConsternationConfig {

    // Data members
    private Customers customers;
//  private ConsternationModulation modulation; // how modulation used to be defined, changed to the int below
    private int modulation;
    private int pointsOfConsternation;

    @XmlJavaTypeAdapter(RectangleStandInAdapter.class)
    private Rectangle window;

    /**
     * Default constructor
    */
    public ConsternationConfig() {
        customers = new Customers();
//      modulation = DEFAULT_MODULATION;  // how modulation used to be defined
        modulation = DEFAULT_MODULATION.ordinal();
        pointsOfConsternation= DEFAULT_POINTS_OF_CONSTERNATION;
        window = new Rectangle(DEFAULT_WINDOW_X, DEFAULT_WINDOW_Y, DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
    }

    public ConsternationModulation getModulation() {
        return ConsternationModulation.values()[modulation];
    }

    public void setModulation(int modulation) {
        this.modulation = modulation;
    }

    public void setModulation(ConsternationModulation modulation) {
        this.modulation = modulation.ordinal();
    }

...a whole bunch of other getters and setters that do nothing but set individual members...
}

And here's ConsternationModulation just for good measure:

public enum ConsternationModulation {

    INVALID,
    FIRST_CONSTERNATION,
    SECOND_CONSTERNATION,
    THIRD_CONSTERNATION,
    FOURTH_CONSTERNATION
}
Frecklefoot
  • 1,660
  • 2
  • 21
  • 52
  • Did you try to use a String parameter to see if it _does_ come in "mangled"? – Paul Samsotha Dec 02 '17 at 00:24
  • Please add your `ConsternationConfig` sources to the question. – Aleh Maksimovich Dec 02 '17 at 16:37
  • @peeskillet, I will as soon as I'm done with some other stuff that came up. That's a great idea. Aleh, added sources to question. – Frecklefoot Dec 04 '17 at 15:25
  • I don't get it. Why do you think `"mode"` should deserialize to `modulation`? The names need to match. – Paul Samsotha Dec 04 '17 at 15:29
  • Okay, I "sanitized" my code before posting it. It should be modulation. I'll change the question. Sorry about that. – Frecklefoot Dec 04 '17 at 16:16
  • This is curious. It works when it's a String. What does this imply? – Frecklefoot Dec 04 '17 at 17:38
  • 1
    Because you still have the the enum method. That's what's being used. I'm not sure exactly what the rules are for having the same name setter method. As far as which one gets chosen, I am not sure what guides this. But I'm thinking this is the problem. – Paul Samsotha Dec 04 '17 at 18:01
  • I was going by the answer to [this question](https://stackoverflow.com/questions/7996335/how-to-match-int-to-enum) regarding the rules of enum conversion. I'll take a look at what's happening in the code. – Frecklefoot Dec 04 '17 at 18:10
  • Okay, I just confirmed that you're right, sort of. As you can see in my code, I had two versions of `setModulation()`. One took an enum, the other took an int. What happened is that _neither_ of them got called. I guess having two "setters" confused the converter, so it just ignored both. Having just the `int` version works. I'll post this as the answer in a while, but if you post it first, @peeskillet, I'll mark it as the answer. – Frecklefoot Dec 04 '17 at 18:26

1 Answers1

0

The problem was the fact that I had two setModulation() methods. One allows the modulation to set with an int, the other with an enum. I thought the conversation would be smart enough to call the appropriate setter (the int setter). I was wrong. Apparently, having two setters confused the converter, so it didn't call either. That explains why it was always at the default value (which is set in the constructor).

Removing the enum version of the setter fixed the problem, and it worked fine afterwards. The setter is shown above, but for convenience, here it is again. There is nothing special or magical about it:

public void setModulation(int modulation) {
    this.modulation = modulation;
}

Thanks for all the input, especially peeskillet!

Frecklefoot
  • 1,660
  • 2
  • 21
  • 52