Skip to content

HAL Forms properties should consider Jackson customizations #680

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
michael-simons opened this issue Dec 9, 2017 · 10 comments
Closed

HAL Forms properties should consider Jackson customizations #680

michael-simons opened this issue Dec 9, 2017 · 10 comments
Assignees

Comments

@michael-simons
Copy link

Hi,

while trying out the new affordance model with the HAL+Forms, I stumbled upon - at least to me - unexpected behavior.

My example is online simple-meetup. There is a resource events and a resource registrations. New registrations come in through a POST on the later, compare here. This works nice and the afforded form is as expected. It uses a dedicated Person as an input.

If I try the same for events through

return new Resources<>(
            eventResources,
            linkTo(methodOn(this.getClass()).events())
                .withSelfRel().andAffordance(afford(methodOn(EventsApi.class).createNewEvent(null)))
        );

in line 75, using the entity / domain entity Event as input, I don't get the expected template.

The HalFormsAffordanceModel uses only the bean properties and this is not what I expected in this case. It returns each and every property of the event.

Given the Jackson Mapping in this class, I am able to use my domain class as more than a dumb hibernate entity. I could introduce a dedicated command object for creating new events which would only expose the required properties as the constructor does at the moment, but that feels wrong.

I could be convinced that introducing a command or request object is the right thing to do in the sense of DDD, but apart from that potential high level discussion it would be nice having the affordance model use the same algorithm as the input mapping does and not the bean utils method.

@odrotbohm
Copy link
Member

… I don't get the expected template.

Can you elaborate more on the expected vs. actual results? Are you saying we're not considering the Jackson configuration you have (e.g. ignored properties etc.)

@michael-simons
Copy link
Author

Yes exactly. Right now the template in the example above presents itself as

"_templates": {
        "default": {
            "contentType": "",
            "method": "post",
            "properties": [
                {
                    "name": "closed",
                    "required": true
                },
                {
                    "name": "full",
                    "required": true
                },
                {
                    "name": "heldOn",
                    "required": true
                },
                {
                    "name": "id",
                    "required": true
                },
                {
                    "name": "name",
                    "required": true
                },
                {
                    "name": "numberOfFreeSeats",
                    "required": true
                },
                {
                    "name": "numberOfSeats",
                    "required": true
                },
                {
                    "name": "open",
                    "required": true
                },
                {
                    "name": "pastEvent",
                    "required": true
                },
                {
                    "name": "registrations",
                    "required": true
                },
                {
                    "name": "status",
                    "required": true
                }
            ],
            "title": null
        }
    }
}

This contains every attribute and method of Event.java.

I was expecting

"_templates": {
        "default": {
            "contentType": "",
            "method": "post",
            "properties": [
                {
                    "name": "heldOn",
                    "required": true
                },
                {
                    "name": "name",
                    "required": true
                }
            ],
            "title": null
        }
    }
}

which fits the constructor marked as JsonCreator:

  public Event(@JsonProperty("heldOn") final LocalDate heldOn, @JsonProperty("name") final String name) {
        this(heldOn, name, 20);
    }

Probably a bit much to ask, but IMHO at least Json-Properties should be recognized… I guess I'm not the only one, who is using them to control how the request body should look.

As I am interested in that topic, a hint into the right direction how to provide this would be nice. If I read the sources correctly, it could be just another implementation of an affordance model.

@odrotbohm
Copy link
Member

Oh, no. A perfectly valid request and a great enhancement. While I'd still argue that the DTO might be a better design decision in general, even those could use Jackson customizations that should be picked up. Usually I rather use Jackson mixins to keep the domain code free of representation specific annotations, but I guess that's a matter of taste to some degree.

@gregturn
Copy link
Contributor

Does Jackson have anything more elegant than scanning each field/getter for annotations?

@gregturn
Copy link
Contributor

...and looking for Jackson constructors?

Nevertheless, I could see a chain of handlers that should be reusable from all affordable models.

@michael-simons
Copy link
Author

Jackson-Mixins or even Jackson-Serializers / Deserializers as Spring-Components. I have them both in my book for exactly the purpose you mention Oliver, but I’m undecided yet.

@odrotbohm
Copy link
Member

@gregturn – Yes, an ObjectMapper has API to inspect Jackson's bean metamodel. We have something similar in Spring Data REST that's then matches them up against Spring Data's PersistentProperty instances. We don't know about the latter in Spring HATEOAS but could simply use the Java PropertyDescriptor abstraction to sort of do the same.

@michael-simons – Restbucks has a completely separate JacksonCustomizations Spring configuration class that does the trick. Keeps everything nicely in one spot.

@odrotbohm odrotbohm changed the title Unexpected outcome of determineAffordanceInputs in HalFormsAffordanceModel HAL Forms properties should consider Jackson customizations Dec 11, 2017
@michael-simons
Copy link
Author

Would that be something I could contribute?

Regarding Restbucks: The example is beautiful.

@odrotbohm
Copy link
Member

odrotbohm commented Dec 11, 2017

@ contribution – Most definitely!

We're going to add HAL Forms support to Spring Data REST going forward and then Spring REStBucks in turn.

@gregturn
Copy link
Contributor

Resolved by #482.

In Collection+JSON I created a utility to handle property extraction and object creation from properties. That solution (driven by this issue) takes Jackson annotations into account. In turn, that PR updates HAL-FORMS to use that utility.

@gregturn gregturn self-assigned this Feb 7, 2019
@gregturn gregturn closed this as completed Feb 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants