#RequestParam spring MVC , make one of two request params mandatory - web-services

I am writing a service wherein I take in either an id or a location and I want to enforce the constraint that either the id or the location must be specified in my #Controller
#Controller
public class HelloController {
#RequestMapping(value="/loc.json",method = RequestMethod.GET)
public #ResponseBody String localiaztionRequest(#RequestParam(value = "location", required = false) String callback
,#RequestParam(value = "id", required = false) String uuid
,#RequestParam(value = "callback", required = false) String callback) {
//model.addAttribute("message", "Hello world!");
return "hello";
}
For clarity, I want each request to send either the location parameter or the id parameter. How do I enforce such a constraint on a pair of input parameters? Also as an aside could someone please explain to me the use of ModelMap , what is the effect of model.addAttribute("message","Hello World!") ?
Sorry if the questions seem rather naive, I'm extremely new to the spring framework.
Thanks in advance.

I think you should split it into two different controller methods
#RequestMapping(value="/loc.json",method = RequestMethod.GET, params={"location"})
public #ResponseBody String localizationRequestByLoc(#RequestParam String location, #RequestParam String callback) {
//model.addAttribute("message", "Hello world!");
return "hello";
}
#RequestMapping(value="/loc.json",method = RequestMethod.GET, params={"id"})
public #ResponseBody String localizationRequestById(#RequestParam String id, #RequestParam String callback) {
//model.addAttribute("message", "Hello world!");
return "hello";
}

One way to accomplish this (although indirect) would be to create a new object model representing the data to be passed in and another representing the data type and requiring both elements.
public enum MethodType
{
First,
Second
}
public class Filter
{
[Required]
public MethodType {get;set;}
[Required]
public string Data {get;set;}
}
use this object for the action method and view
and let the action method in the controller convert the object

Related

Update User defined object of the dynamoDb item using UpdateItemRequest

We have a DynamoDB table Test which has an attribute Template. Bellow are the class definitions. I would like to update the Template attribute or some of its attribute based on certain condition. I tried doing the same using UpdateItemRequest but unable to find a way to update the template attribute since everything is converted to either string, number or bytes.
Code for reference.
#DynamoDbBean
public class Test implements NoSQLEntity {
private String name;
private Template template;
#DynamoDbAttribute("name")
public String getName() {
return name;
}
#DynamoDbAttribute("template")
public Template getTemplate() {
return template;
}
}
#DynamoDbBean
public class Template {
private String pk;
private String name;
private List<String> demo;
#DynamoDbAttribute("pk")
public String getPk() {
return this.pk;
}
#DynamoDbAttribute("name")
public String getName() {
return name;
}
#DynamoDbAttribute("demo")
public List<String> getdemo() {
return demo;
}
}
Sample update code:
UpdateItemRequest request = UpdateItemRequest.builder()
.tableName("Test")
.key(itemKey)
.updateExpression("SET tmpt = :tmt")
.expressionAttributeValues(expressionValues)
.build();
Here I am unable to build the :tmt using the AttributeValue. Can someone please guide me?
Here is a Readme from the Eng team that you may find useful:
https://github.com/aws/aws-sdk-java-v2/tree/master/services-custom/dynamodb-enhanced
DynamoDb Enhanced provides DefaultAttributeConverterProvider that will identify a converter that can convert the specific Java type into the AttrbuteValue type that can used to update the item.
Smaple Code:
AttributeValue value = DefaultAttributeConverterProvider.create()
.converterFor(EnhancedType.documentOf(Template.class,
TableSchema.fromBean(Template.class)))
.transformFrom(template);
Can then put this value in the expressionValues map.
Map<String, AttributeValue> expressionValues = new HashMap<>();
expressionValues.put(":tmt", value);
UpdateItemRequest request = UpdateItemRequest.builder()
.tableName("Test")
.key(itemKey)
.updateExpression("SET tmpt = :tmt")
.expressionAttributeValues(expressionValues)
.build();

Spring Data Neo4j custom query list params not use converter

NodeEntity:
#NodeEntity(label = "User")
public class UserNode {
#GraphId
private Long _gid;
#Index(unique = true, primary = true)
#Convert(ObjectIdConverter.class)
private ObjectId id;
}
Converter:
public class ObjectIdConverter implements AttributeConverter<ObjectId, String>{
#Override
public String toGraphProperty(ObjectId value) {
return ObjectIdUtils.compressed(value);
}
#Override
public ObjectId toEntityAttribute(String value) {
return ObjectIdUtils.uncompress(value);
}
}
Repository:
public interface UserNodeRepository extends GraphRepository<UserNode> {
#Query("MATCH (user:User) WHERE user.id IN {0} RETURN user")
List<UserNode> findByIdIn(List<ObjectId> ids);
}
UserNodeRepository#findByIdIn is custom query. but the request parameter directly convert to json without using ObjectIdConverter.
Log:
o.n.o.drivers.bolt.request.BoltRequest : Request: MATCH (user:User) WHERE user.id IN {0} RETURN user with params {0=[{timestamp=1500442853, machineIdentifier=11302907, processIdentifier=11906, counter=4709865, time=1500442853000, date=1500442853000, timeSecond=1500442853}, {timestamp=1500445335, machineIdentifier=11302907, processIdentifier=11906, counter=4709946, time=1500445335000, date=1500445335000, timeSecond=1500445335}, {timestamp=1500447522, machineIdentifier=11302907, processIdentifier=11906, counter=4710014, time=1500447522000, date=1500447522000, timeSecond=1500447522}, {timestamp=1500448399, machineIdentifier=11302907, processIdentifier=11906, counter=4710092, time=1500448399000, date=1500448399000, timeSecond=1500448399}]}
Is this the SDN expectation or what concepts have I lost?
This is not possible for finders with custom #Query. There is no way for OGM to know that your parameter relates to a property with #Convert annotation (the method name is not used at all). To solve this convert to your property type manually instead and use that as a parameter:
#Query("MATCH (user:User) WHERE user.id IN {0} RETURN user")
List<UserNode> findByIdIn(List<String> ids);
However this works fine for derived finders - OGM knows the field, and the #Convert annotation with the right converter, from the method name.
Example with single parameter:
List<UserNode> findById(ObjectId id);
Unfortunately there seems to be a bug for the IN operator and a collection parameter with:
// doesn't work
List<UserNode> findByIdIn(List<ObjectId> ids);
I have created a jira issue.

How to use SPEL along with regex in RequestMapping

I have a controller method as follows
#RequestMapping(value = "/{fruitName:Mango|Orange|Grapes}", method = RequestMethod.GET)
public String viewFruit(ModelMap model, #PathVariable String fruitName) {
...
}
Here I am hard-coding Mango, Orange and Grapes, such that if url matches with any of these, then only this method should execute.
What I want to do is that, instead of hard-coding these fruits here. I want to declare them in a properties file and by using SPEL, I should bring it here.
Is this possible to do?
I tried code below for this, but failed with error:
#RequestMapping(value = "/{fruitName:#{fruit['seasonFruit.requestMapping']}}", method = RequestMethod.GET)
public String viewFruit(ModelMap model, #PathVariable String fruitName) {
...
}
For following properties File (fruit.properties)
seasonFruit.requestMapping = Mango|Orange|Grapes
Please suggest, how this could be achieved?
#ArtemBilan So, isn't there any way by which we could achieve this? By separation of hard coding
Well, I hope you can do that from code:
#Value("#{ environment['seasonFruit.requestMapping'] }")
private String fruitName;
#RequestMapping(value = "/{fruitName:[a-z]", method = RequestMethod.GET)
public String viewFruit(ModelMap model, #PathVariable String fruitName) {
if (fruitName.matches(this.fruitName))
}
You may not be able to use combination of REGEX and values loaded from property files in requestMapping directly. But i am able to achieve in a sample app. Essentially i am resolving the entire regex pattern from property file, not just values of it. RequestMapping can resolve values from properties file.Hope this helps.
Property file
sample.test={url:mango|orange}
Controller method:
#RequestMapping(value = { "/example/${sample.test}" }, method = RequestMethod.GET)
public String testPattern(#PathVariable String url) {
System.out.println("url:" + url);
return sample;
}

How to send a property as a string in RestEasy response?

I have a class called Product which has a property called id of type long. Below is the class
public class Product {
private long id;
}
The value of id is beyond the value which javascript can handle. I realized this after seeing the below link
Parse json in javascript - long numbers get rounded
I dont want to declare the field as String in the domain class. But I want to say to RestEasy that it has to send the value as a string in the json response.
How can I do this? I dont want to use any third party api. Is it possible in RestEasy. I have gone through the documentation but did not find any such annotation or may be I did not go through the documentation properly.
Can anyone please help. Thanks all in advance.
If you are using Jackson as JSON Serializer you can extend the JacksonJsonProvider:
#Provider
public class JsonProvider extends org.codehaus.jackson.JacksonJsonProvider {
public JsonProvider() {
ObjectMapper objectMapper = locateMapper(ObjectMapper.class, MediaType.APPLICATION_JSON_TYPE);
objectMapper.configure(org.codehaus.jackson.JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);
}
}
If you are using Jettison you can register a custom XmlAdapter:
public class LongAdapter extends XmlAdapter<String, Long> {
#Override
public String marshal(Long id) throws Exception {
if (id == null) {
return "";
}
return id.toString();
}
#Override
public Long unmarshal(String id) throws Exception {
return Long.parseLong(id);
}
}

WCF+WebService: 2 fields are generated to represent 1 integer

In my WCF service I have method with 'int' parameter:
[OperationContract]
PublishResult PublishEnrollmentProfile(
string siteName, int methodId,...
);
When I created WebService reference to this WCF service the following signature was generated:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("...",
RequestNamespace="...", ResponseNamespace="...",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return: System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
public PublishResult PublishEnrollmentProfile(
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
string siteName,
int methodId,
[System.Xml.Serialization.XmlIgnoreAttribute()]
bool methodIdSpecified, ...)
{
object[] results = this.Invoke("PublishEnrollmentProfile", new object[] {
siteName,
deployServerName,
methodId,
methodIdSpecified,
deviceClass,
deviceName,
registrationCode});
return ((PublishResult)(results[0]));
}
You can see that instead of one integer parameter I've got 2: integer (for value) and bool (for mark 'if value was specified).
Is this ok? Why do I need the 2nd parameter (bool)?
Thanks a lot!
Specified" fields are only generated on optional parameters that are structs. (int, datetime, decimal etc). All such variables will have additional variable generated with the name Specified.
Since the "Specified" fields are only generated on optional parameters, if you placed the parameters for the PublishEnrollmentProfile method inside of a DataContract and set the DataMember attribute on methodID to [DataMember(IsRequired=true)] the specified field should go away, unless this is an optional field in which case you would want to leave it how it is.
Here's a blog posting with some samples.
UPDATE
So you have your Operation Contract.
[OperationContract]
PublishResult PublishEnrollmentProfile(string siteName, int methodId,...);
If the parameters of that method are not optional then you should create a DataContract and redefine the OperationContract like so:
{
[OperationContract]
PublishResult PublishEnrollmentProfile(PublishEnrollmentProfileRequest request);
}
And then you have your DataContract like this.
[DataContract]
public class PublishEnrollmentProfileRequest
{
private string _siteName;
[DataMember]
public string siteName
{
get;
set;
}
private int _methodId;
[DataMember(IsRequired=True)]
public int methodId
{
get;
set;
}
.
.
.
}
So you have a "request" object that you pass into the WCF service which has fields siteName and methodId. In the example I provided methodId is now required, this would elminate the "Specified" field.