I am using #ProjectedPayload on an interface to bind a JSON request body to a proxied instance of my interface.
My interface is as follows (in Kotlin, the val just translates to a Java getter):
#ProjectedPayload
interface ImportServer {
val id: UUID?
val name: String?
}
Now, the id here is completely optional, but there is no way for me to specify that, at least as far as I can tell. If I try to access the id property without it being present in the request body I will receive an exception from JsonPath: com.jayway.jsonpath.PathNotFoundException: No results for path: $['id']. If I could configure JsonPath I could use Option.DEFAULT_PATH_LEAF_TO_NULL and I'd get null for elements that are not present. But there is no way for me to get at the JsonPath configuration, it happens locked away inside JsonProjectingMethodInterceptorFactory.
Is there a way for me to specify a default here? Or is there a way for me to detect if the id is present without accessing the id property in the first place?
That's a bug and has been fixed with DATACMNS-1145. Will be released with Ingalls SR7 and transitively with Boot 1.5.7.
Related
I am using OpenAPI / Swagger to specify my API.
One thing that I could not find out is how to specify a Set.
I am using https://editor.swagger.io/ and I typed in the whole API. For a property that I want to specify as Set I wrote the following:
myProperty:
uniqueItems: true
type: array
description: some description
items:
type: string
I would have guessed that uniqueItems does the trick and a Set is generated, but this is not the case. Instead the following code is generated:
#JsonProperty("myProperty")
private List<String> myProperty = null;
Is there a way to generate something like
#JsonProperty("myProperty")
private Set<String> myProperty = null;
instead?
I found a possible solution here in SO, but this requires some configuration in a pom.xml. However, the online editor that I am using gives me only the option to generate code for different platforms but does not accept a pom file.
OpenAPI (version 3) supports the following data types:
string
number
integer
boolean
array
object
There is no support for set data type in OpenAPI v3. The closest data type is an array with property uniqueItems set to true (as you've suggested). But it's still an array with a constraint on the uniqueness of its items, not a set.
So, your request cannot be resolved on the OpenAPI level.
However, there might be an option on the code generator level, and you would need to address the issue to the code generator of your choice.
I stumbled upon some code that adds JsonIgnoreProperties to a property that doesn't exists in class, but exists in JSON, e.g.:
#JsonIgnoreProperties({"ignoreprop"})
public class VO {
public String prop;
}
When JSON is
{ "prop":"1", "ignoreprop":"9999"}
I wonder if ignoring properties has any advantage(s) performance-wise or is it just redundant code?
Annotation that can be used to either suppress serialization of properties (during serialization), or ignore processing of JSON properties read (during deserialization).
EDIT
Is there an advantage(s) ignoring specific property over all (with
#JsonIgnoreProperties(ignoreUnknown=true))?
I wonder if ignoring properties has any advantage
Yes, it is used a lot for forward-compatibility in services. Let's say you have Services A and B. Currently A sends requests to B with some JSON objects.
Now you want to support a new property in the JSON. If you have this feature you are able to let A start sending the new property before B knows how to handle it. Decoupling the development processes of those two services.
ignoring specific property over all
This case does have some minor performance advantages. First, it doesn't try to parse this property which can be a simple string or complex object/array. Second, it helps you avoid handling an exception. Think that all the following can be valid calls and you only care about prop:
{ "prop":"1", "ignoreprop":"9999"}
{ "prop":"1", "ignoreprop":{ "a": { "key": "value", "foo": false }}}
{ "prop":"1", "ignoreprop":[1,2,3,4,5,6..... 1000000]}
From the documentation, mainly the purpose of use this is To ignore any unknown properties in JSON input without exception: which is better not to popup exception when properties are not found either in class or JSON, and this might helps serializing faster docs
Example:
// to prevent specified fields from being serialized or deserialized
// (i.e. not include in JSON output; or being set even if they were included)
#JsonIgnoreProperties({ "internalId", "secretKey" })
// To ignore any unknown properties in JSON input without exception:
#JsonIgnoreProperties(ignoreUnknown=true)
Starting with 2.0, this annotation can be applied both to classes and to properties. If used for both, actual set will be union of all ignorals: that is, you can only add properties to ignore, not remove or override. So you can not remove properties to ignore using per-property annotation.
I am trying to make my #webparam mandatory using (#XmlElement(required=true) but the generated XSD still shows this as minOccurs="0". Also tried setting nillable=false but still not working.
Here is my web method :
#WebMethod
#WebResult(name = "Biller")
public Biller getBiller(#XmlElement(required=true) #WebParam(name = "billerId") Integer billerId){}
Please suggest.
As specified by me in comments - either you need to wrap your Integer variable into some Java POJO and apply rules for specific fields in that POJO or change to primitive type because - reference types are always optional but constituent fields of wrapper types can be made required or optional.
Primitive types are always required.
Refer this answer
Then comes the question about default values - and for that refer Answers to this question and summary is - if nothing is specified -
minOccurs and maxOccurs default to 1
Now why your call succeeds with SOAP UI - Your xsd is correct and that is acknowledged by SOAP UI so my guess is client might be attaching some default values when its missing. I haven't used SOAP UI. Try examining your request ans see if value is really missing. If value is indeed missing in request then try to examine as why validation is not kicking in.
I want to set null value to entity by sending null request.
For example:
PATCH: "{deleteDate: null}" to http://localhost/api/entity/1
But it doesn't work.
I found here information how PATCH requests processed:
An new instance of Foo is created
Foo is populated with all values that have been sent with the request
The Foo entity with the id provided by the URI is loaded
All properties that differ between the two objects are copied from the new Foo to the persisted Foo, unless the value is null in the new Foo.
Do I understand correctly that it is impossible to set value to NULL with PATCH request to spring-data-rest service API?
In Spring context null values in PATCH method means that there are no changes.
If you want write null values you can
1) use PUT method;
2) implement your own DomainObjectMerger class, in which you can extend method merge with condition like
sourceValue != targetValue;
3) use DomainObjectMerger.NullHandlingPolicy configuration.
Depends on your Spring Data REST version.
All 3 options from egorlitvinenko's answer will solve the described problem but will have another one:
All other properties which were not specified in PATCH request would be "nullified" too.
Seems like spring-data-rest, issue-345 was already fixed in v2.2.x.
I have a created a custom field in Contacts object in Salesforce whose API name is "Resume_Text__c" and I'm making a SOAP call to get the value of that filed using Java Implementation by writing a following SOQL.
SELECT Resume_Text__c FROM Contact
But execution of query throwing following exception.
No such column 'Resume_Text__c' on entity 'Contact'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.'
So how can I access custom field via Soap API Java Implementation?
Whenever you are using Enterprise.wsdl file in your implementation, you need to make sure that every time you create some new fields and object on Salesforce.com environment, you refresh your Enterprise.wsdl to import all the dependency mappings else go with Partner.wsdl.