Mapping of Dynamic fields in RestfulController POST (save) method - spring-boot

How do I enable RestfulController to auto-map or even manually map the dynamic fields to domain classes implementing MongoEntity? I have a domain class as below:
class Company implements MongoEntity<Company> {
String id = UUID.randomUUID().toString()
String name
String email
String phone
}
And I have a RestfulController setup for CRUD operations as below
class CompanyController extends RestfulController<Company> {
#Transactional
def save(Company company) {
if(company.hasErrors()) {
respond company.errors
}
else {
company.insert(flush:true)
respond company, status: CREATED
}
}
}
When I POST a request with some additional JSON fields, how do I get them auto-mapped to gorm_dynamic_attributes ? Currently the company object does not return any information on the dynamic attributes. Another problem I am facing is that request.JSON is also null so I cannot manually map either. Any suggestions would be highly appreciated.

I'm pretty sure, that the problem is not in data binding of your controller, but rather in persisting of the domain class instance.
I would change the domain class like so:
import grails.gorm.annotation.Entity
#Entity
class Company {
String id
String name
String email
String phone
def beforeValidate() {
if( !id ) setId UUID.randomUUID().toString()
}
static mapping = {
id generator:'assigned'
}
}
to use the assigned generator. You could put your id generation either in the controller / service code, or leave it inside the domain class' beforeValidate. In the later case pay special attention to when the id shall be generated, as beforeValidate() is called pretty often. Also note, that inside beforeValidate() a setter must be called.
I tested the similar domain class of mine with save() and insert() and in both cases that works like charm.

Related

Bind json value to two object in spring MVC restful

At present what I have is one view in HTML for entering Person's details and Company's details. I am using spring MVC framework restful.
I create json and send request using Ajax to Restcontroller.based on URL pattern create method is called .e.g. json is
{"name":"rohit","address":"Pune","company":"ABC"}
Here above name and address belong to person bean and company belongs to company bean. I want the json value bind to their respective bean. How to do it? I have tried the code below but I know it won't work.
#Requestmapping(value="/createperson",method=method.post)
public #Responsebody String createperson(#Requestbody person,#Requestbody company)
{
//Some code to save
}
I have a form, which will input the person's details and the person's company details.
What I want is that when this form is submitted, some of its fields are bound to Person object properties and some to Company object properties. How can this be done? And how to do validation for json value and send all errors as json responsive again back if there are any errors.
You can only have one #RequestBody. Spring then looks at the content-type header and finds an appropriate HttpMessageConverter which will read the entire http entity body (input stream) into a single object.
What you have basically done is try to merge Person and company into a single JSON object, and thereby flattened the structure. If you want spring to handle that, you need to create a new object with the same (flat) hierarchy. Or you need to create a wrapper class PersonAndCompany which contains both a Person and a Company, and then change the JSON to match the structure, so it looks like this.
{
"person" : {
"name":"rohit",
"address":"Pune"
},
"company" : {
"name":"ABC"
}
}
you should do like this if you are using relationship between Person and Company otherwise it is better to use single bean instead of two.
#ResponseBody
#RequestMapping(value = "/createperson", method=RequestMethod.POST ,consumes=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Person> createperson(#RequestBody Person person) {
if(error found ){
Person p new Person();
p.setError(" error message ");
return new ResponseEntity<Person>(p,HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<Person>(person,HttpStatus.OK);
}
public class Person {
private String name;
private String address;
Company company;
String error;
--- setters getters
}
public class Company {
String compName;
--- setters getters
}
input json
{"name":"person name ","address":"person address ","company":{"compName":"company name"}}

Where to validate DTO

I am writing a Webservice which sends and receives DTO's
A DTO might look like this(in this example its C#)
[Serializable]
public class GetCardStatusRequest : RequestBase
{
public GetCardStatusRequest()
{
}
public String CardId { get; set; }
}
when receiving such a request DTO I want to validate that the CardId is for example not empty.
So I currently have a validation class
internal class Validation
{
internal static bool IsValidGetGiftCardStatusRequest(GetCardStatusRequest getCardStatusRequest)
{
return getCardStatusRequest.CardId != null && !string.IsNullOrEmpty(getCardStatusRequest.CardId);
}
}
There are more "complex" DTO's so I wanted to place the validation logic somewhere to ensure that the incoming requests are valid before mapping them to the business objects.
My question is where should I place the validation logic and how should I do it ? I currently have this class with only static methods which seem wrong to me.
Should this validation be placed in the service layer ?
I feel quite close with this logic above, but nevertheless it seems not correct.

Web api controller with multiple post methods with the same name but with different parameters

I have web api controller that has multiple post methods with the same name but with different parameters; when i run the application, i got an error:-
Multiple actions were found that match the request
note:- I don't want to use Action Routing as i want to unify my clients who use my web api
public Customer Post(Customer customer)
{
}
public Product Post(Product product)
{
}
The problem is that there's no way to distinguish between those two Post methods based on the URL that's getting passed to the web api.
The way to handle this would be to use a separate controller. One controller would be "api/Customer" and would have Post method that takes a Customer:
public class CustomerController : ApiController
{
public Customer Post(Customer customer) { }
}
The other would be "api/Product" and take a Product:
public class ProductController : ApiController
{
public Product Post(Product product) { }
}
If you really really wanted to pass both into one controller, you could create a class that has all the properties of both Customer and Product, and then look at the properties to figure out what just got passed into your controller. But... yuck.
public class EvilController : ApiController
{
public ProductOrCustomer Post(ProductOrCustomer whoKnows)
{
// Do stuff to figure out if whoKnows has
// Product properties or Customer properties
}
}
You could use a single controller, with a single method taking a parameter of an interface type that both classes implement. Then call private handlers based on runtime type.

mvc3 validation when using buddy classes

I am working on an mvc3 application and having some problems with getting validation to work as I want.
The application is using buddy classes for the models. (This is something I haven't used in the past and I am a little confused why they are used...anyway)
I want to add required fields to ensure data been submitted is correct. I have tried adding the required field to the buddy class.
When I submit the form no client-side validation takes place and the debugger steps into the entity frameworks generated code. Here is complains that the fields that contain null values are causing are invalid. If I step through all of those it finally gets to the controller where my if (ModelState.IsValid) is showing false.
I have client-side validation switched on.
Am I meant to be applying the data validation at the buddy class level or at the view model?
One other question is why use buddy classes? to me they seem to over complicate things.
Updated added an example of the buddy class
[MetadataType(typeof (CustomerMetaData))]
public partial class Customer
{
public string Priorty
{
get
{
var desc = (Priority) Priority;
return desc.ToString().Replace('_', ' ');
}
}
internal class CustomerMetaData
{
[Required]
[DisplayName("Priorty")]
public string Priorty { get; set; }
Buddy classes are metadata classes to put data annotation attributes when you are not in control of the original class i.e. can't edit it. Typical situation is when the class is generated by an ORM like Entity Framework.
//Can't edit this class
public partial class YourClass{
public string SomeField {get; set;}
}
//Add a partial class
[MetadataType(typeof(YourClassMetadata))]
public partial class YourClass{
}
//And a metadata class
public class YourClassMetadata
{
[Required(ErrorMessage = "Some Field is required")]
public string SomeField {get; set;}
}
are you sure that you have [MetadataType(typeof(YourClassMetadata))]?
More about buddy classes here and here
You would typically use a buddy class when it isn't possible to add meta data to an entity class such as when a model is automatically generated by an ORM tool. In this case any meta data you had applied would be lost.
Therefore, your original (automatically generated) class would be defined as a partial class:
public partial class Customer
{
public string Priority { get; set; }
}
And then you would generate your buddy classes to add the meta data.
[MetadataType(typeof(CustomerMetaData))]
public partial class Customer
{
}
internal class CustomerMetaData
{
[Required]
public string Priority { get; set; }
}
You would then pass the Customer class to the view where the Priority would be set.
In your case i'm not sure if you only have one partial class or two (as the other is not shown but please provide if there is). I'm interested to know how you obtain the priority information from the customer as i'm wondering if this is an issue with how you use ModelState.IsValid? The reason I ask is that no set accessor is declared on the Priority property so i'm wondering how this is set from the view in order to report that it is not valid?
You would also use a buddy class when it isn't possible to add meta data to an entity class such as when a model is automatically generated by an WCF Data Contract.

How do I inject something into request header for testing?

I am currently implementing SiteMinder for the site, which looks for a key called SM_USER in the request header. I retrieve it using the function below:
public string ReadUser()
{
return HttpContext.Current.Request.Headers["SM_USER"];
}
I wish to test if functionality releated to this function work; I have already tried unit testing using a mock class so I am looking to create the key SM_USER in the request header. How can I do that?
I am implementing the application with MVC3.
As long as you are using HttpContext.Current you will not be able to test it as Unit Test will not have HttpContext.Current.
Try to use an Interface with method returning string, say ReadUser(). Implement this interface in a class in your application. Use the interface variable whichever class you are using this method in. In that class' default constructor set that interface variable value to 'new' implementer class. Add an overload of the constructor which will take a parameter of type interface and set that parameter to interface variable.
Now in your UnitTest project implement same interface in another class. In this implementation you can now pass whatever mock value you want test.
public interface IReadUserInfo
{ string ReadUser(); }
public class ReadUserInfo: IReadUserInfo
{
public string ReadUser()
{
return HttpContext.Current.Request.Headers["SM_USER"];
}
}
public class UserClass
{
IReadUserInfo userinfo;
public UserClass()
{
userinfo = new ReadUserInfo();
}
public USerClass(IReadUserInfo newuserinfo)
{
userinfo = newuserinfo;
}
}
public class TestReadUserInfo : IReadUSerInfo
{
public string ReadUser()
{ return "testvalue"; }
}
If ReadUser is the only value you are using from Request header, then this approach will solve the problem. However, if you using more values from Request object, you might want to mock entire request object in similar way.

Resources