Why I am getting null vales in #RequestBody Parameters? - rest

I have created a simple REST service (POST). But when I call this service from postman #RequestBody is not receiving any values & getting nullPointer.
#RequestMapping(value=/searchEmployee,method = RequestMethod.POST,produces=MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<List<EmpDTO>> search(#RequestBody EmpSearchDTO empSearchDTO){
String brId=empSearchDTO.getBrid();// null
List<String> location=empSearchDTO.getLocation()//null
Employee e=employeeRepository.findByEmployeeBrId(String brId);
}
My java Bean object is like below:
public class EmpSearchDTO{
private String brId;
private List<String> location;
public void setBrid(String brId){
brId=brId;
}
public String getBrid(){
return brId;
}
public void setLocation(List<String location){
location=location;
}
public List<String> getLocation(){
return location;
}
}
JSON which I am passing in request body is
empSearchDTO
{
"brId":"G1234",
"location":["India"]
}

Related

Feign - define param value for each methods

I need to write a client with multiple methods that require the apiKey as query string param. Is it possible to allow the client's user to pass the api key only to the method withApiKey, so I can avoid to request the apiKey as first parameter of each method?
public interface Client {
#RequestLine("GET /search/search?key={apiKey}&query={query}&limit={limit}&offset={offset}")
SearchResponse search(#Param("apiKey") String apiKey, #Param("query") String query, #Param("limit") Integer limit, #Param("offset") Integer offset);
#RequestLine("GET /product/attributes?key={apiKey}&products={products}")
List<Product> getProduct(#Param("apiKey") String apiKey, #Param("products") String products);
public class Builder {
private String basePath;
private String apiKey;
public Client build() {
return Feign.builder()
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.client(new ApacheHttpClient())
.logger(new Slf4jLogger())
.logLevel(Logger.Level.FULL)
.target(Client.class, basePath);
}
public Builder withBasePath(String basePath) {
this.basePath = basePath;
return this;
}
public Builder withApiKey(String apiKey) {
this.apiKey = apiKey;
return this;
}
}
}
Depending on the setup request-interceptors might work: https://github.com/OpenFeign/feign#request-interceptors
Hopefully the example below will help.
You can swap the builder out for just the interface annotation and then move the configuration to a configuration class, if you are using spring it could be like:
#FeignClient(
name = "ClerkClient",
url = "${clery-client.url}", // instead of the withBasePath method
configuration = {ClerkClientConfiguration.class}
)
public interface Client {
Then the ClerkClientConfiguration class can define the required config beans including a ClerkClientInterceptor
public class ClerkClientConfiguration {
#Bean
public RequestInterceptor clerkClientInterceptor() {
return new ClerkClientInterceptor();
}
Then the interceptor can have a value picked up from the config and added to the queries (or header etc)
public class ClerkClientInterceptor implements RequestInterceptor {
#Value("${clerk-client.key}")
private String apiKey
#Override public void apply(RequestTemplate template) {
requestTemplate.query( "key", apiKey);
}

play2 java form binding - how to set field name to map to object?

Say I have the below test case
I want to be able to bind camel case parameters:
anyData.put("my_id", "bob#gmail.com");
How can I get this test to pass??
public class FormBindingExampleTest {
public static class FormBindingExampleModel {
public String myid;
public String email;
public String getMyid() {
return myid;
}
public void setMyid(String myid) {
this.myid = myid;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
#Test
public void itShouldBindForm(){
Form<FormBindingExampleModel> userForm = form(FormBindingExampleModel.class);
Map<String,String> anyData = new HashMap();
anyData.put("my_id", "bob#gmail.com");
anyData.put("email", "secret");
FormBindingExampleModel user = userForm.bind(anyData).get();
System.out.println(user.myid);
assert(user.myid.equals("bob#gmail.com"));
}
}
Use form's fill() method inorder to populate the form with existing value.
#Test
public void itShouldBindForm(){
Form<FormBindingExampleModel> userForm = form(FormBindingExampleModel.class);
FormBindingExampleModel formModel = new FormBindingExampleModel();
formModel.setMyid("bob#gmail.com");
formModel.setEmail("secret");
userForm.fill(formModel);
FormBindingExampleModel user = userForm.get();
System.out.println(user.getMyid);
assert(user.getMyid.equals("bob#gmail.com"));
}
Documentation available here.

RequestFactory ValueProxy class with embedded List of another ValueProxy not visible in response on client

I have a requestfactory service request that returns a List<> of RoleProxy. The RoleProxy contains a List<> of PermissionProxy. I can see the data coming back from the server. I can see it in the data that is being parsed by the AutoBean decode. But the response RoleProxy in the onSuccess method does not have any data in it's List<>.
Here is the RoleProxy
#ProxyForName("com.ihg.atp.schema.crs.revenue.sbrpa.datatypes.v1.RolesType")
public interface RoleProxy extends ValueProxy {
public int getId();
public void setId(final int id);
public String getName();
public void setName(final String name);
public List<PermissionProxy> getPermissions();
public void setPermissions(final List<PermissionProxy> permissions);
}
The Permissions Proxy
#ProxyForName("com.ihg.atp.schema.crs.revenue.sbrpa.datatypes.v1.PageType")
public interface PermissionProxy extends ValueProxy {
public String getPageIndex();
public void setPageIndex(final String pageIndex);
public String getAccessType();
public void setAccessType(final String accessType);
}
And the calling routine
RolesContext ctx = requestFactory.rolesContext();
ctx.getAllRoles().with("permissions").fire(new Receiver<List<RoleProxy>>() {
#Override
public void onSuccess(List<RoleProxy> response) {
#SuppressWarnings("unused")
List<PermissionProxy> perms = response.get(0).getPermissions();
// Here perms is an empty list instead of the data that was sent
}
});
Does anyone have an idea of what is happening here? I have done similar things in the past with EntityProxies.
On Edit: Added link to response body.

Defining a resource assembler for a REST Spring HATEOAS controller

I'm trying to add HATEOAS links to a JSON resource served by a Spring REST controller.
I see I should use a resource assembler as described at https://github.com/spring-projects/spring-hateoas
The example displays a Person class and a PersonResource class.
I understand the PersonResource class is defined as:
public class PersonResource extends ResourceSupport {
}
What is then the Person class ? Is it a data domain class ?
In my case, I have defined an Admin class that is a REST domain class, and I specified it as having resource support:
public class Admin extends ResourceSupport {
private String firstname;
private String lastname;
private String email;
private String login;
private String password;
private String passwordSalt;
public Admin() {
}
public String getFirstname() {
return this.firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return this.lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getLogin() {
return this.login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPasswordSalt() {
return passwordSalt;
}
public void setPasswordSalt(String passwordSalt) {
this.passwordSalt = passwordSalt;
}
public EventAdmin toEventAdmin() {
EventAdmin eventAdmin = new EventAdmin();
BeanUtils.copyProperties(this, eventAdmin);
return eventAdmin;
}
public static Admin fromEventAdmin(EventAdmin eventAdmin) {
Admin admin = new Admin();
BeanUtils.copyProperties(eventAdmin, admin);
return admin;
}
}
My REST controller sees only this Admin class as it is a REST domain class. It does not know, and should not know, of anything data domain class.
So I wonder how to use the resource assembler support here.
I don't understand why I should have an additional data domain Admin class here.
kind Regards,
Following Mike's answer here is how my controller now looks like:
#RequestMapping(method = RequestMethod.POST, produces = "application/json; charset=utf-8")
#ResponseBody
public ResponseEntity<Admin> add(#RequestBody Admin admin, UriComponentsBuilder builder) {
AdminCreatedEvent adminCreatedEvent = adminService.add(new CreateAdminEvent(admin.toEventAdmin()));
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type", "application/json; charset=utf-8");
responseHeaders.setLocation(builder.path("/admin/{id}").buildAndExpand(adminCreatedEvent.getAdminId()).toUri());
Admin createdAdmin = adminResourceAssembler.toResource(adminCreatedEvent.getEventAdmin());
ResponseEntity<Admin> responseEntity = new ResponseEntity<Admin>(createdAdmin, responseHeaders, HttpStatus.CREATED);
return responseEntity;
}
Before, instead of using the resource assembler I was doing a:
Admin createdAdmin = Admin.fromEventAdmin(adminCreatedEvent.getEventAdmin());
createdAdmin.add(linkTo(methodOn(AdminController.class).add(createdAdmin, builder)).withSelfRel());
But it was not giving me the resource id in the url.
Your ResourceAssembler implementation needs to know about both the data domain class and the REST domain class, because its job is to convert the former to the latter.
If you want to keep knowledge of your data classes out of your controller, you could make a resource conversion service which would retrieve the data from the repo and use a ResourceAssembler to turn it into resources that the controller can know about.
#Component
public class AdminResourceAssembler extends ResourceAssemblerSupport<Admin, AdminResource> {
public AdminResourceAssembler() {
super(AdminController.class, AdminResource.class);
}
public AdminResource toResource(Admin admin) {
AdminResource adminResource = createResourceWithId(admin.getId(), admin); // adds a "self" link
// TODO: copy properties from admin to adminResource
return adminResource;
}
}
#Service
public class AdminResourceService {
#Inject private AdminRepository adminRepository;
#Inject private AdminResourceAssembler adminResourceAssembler;
#Transactional
public AdminResource findOne(Long adminId) {
Admin admin = adminRepository.findOne(adminId);
AdminResource adminResource = adminResourceAssembler.toResource(admin);
return adminResource;
}
}
#Controller
#RequestMapping("/admins")
public class AdminController {
#Inject private AdminResourceService adminResourceService;
#RequestMapping(value="/{adminId}", method=RequestMethod.GET)
public HttpEntity<AdminResource> findOne(#PathVariable("adminId") Long adminId) {
AdminResource adminResource = adminResourceService.findOne(adminId);
return new ReponseEntity<>(adminResource, HttpStatus.OK);
}
}

POJO information lost during RPC call (GWT)

I am having issues with RPC calls and GWT. Essentially, I have a Person class (common code between client and server) that is created in the client side web code, sent to the server code via an RPC call, and then saved to a DB (OrientDB). I have verified that the following work:
RPC call - I am able to send info to the server and retrieve info from the server
save to DB - have verified that a Person object is saved to the DB
Where I am having issues is the transfer of the POJO from the client to the server. I have verified that the POJO's properties are intact right before it is sent to the server, however, the object passed to the server contains null values for all properties. Essentially, the class is transferred but the information is not. It then saves to the DB, but obviously without any relevant information contained within it.
I will copy what I feel is relevant below, please let me know what else I can provide to make this problem easier to identify. Note these are still in a testing state, so mind the comments :)
Any idea why my POJO's information is being lost in translation?
Person object, followed by the abstract class it inherits from:
public class Person extends org.matesweb.shared.AbsPerson implements Serializable
{
#Id
private String id; // DON'T CREATE GETTER/SETTER FOR IT TO PREVENT THE CHANGING BY THE USER APPLICATION,
// UNLESS IT'S NEEDED
//sets new user details
public void setPerson(String fIrstName, String mIdInit, String lAstName, String email, String password)
{
firstName = fIrstName;
middleInitial = mIdInit;
lastName = lAstName;
}
/*getter and setter methods - required for every
* field due to restrictions imposed by OrientDB*/
public Object getId()
{
String tmp;
tmp = id.toString();
return tmp;
}
//end class
}
public class AbsPerson implements Serializable
{
String firstName;
String middleInitial;
String lastName;
// public sys.Login login;
public org.matesweb.shared.Group[] groups;
private org.matesweb.shared.Purchase[] purchases;
/*this method adds a new purchase to the purchases variable*/
/* public void addPurchase(float price, String description)
{
people.Purchase newPurchase = new people.Purchase(login, price, description);
}
*/
/*adds a person to a group by comparing the passed in group ID and PWD*/
public void addGroup(String groupID, String groupPWD)
{
//compare group ID with group PWD to add a user to the group
}
/*getter and setter methods - required for every
* field due to restrictions imposed by OrientDB*/
public String getFirstName()
{
return firstName;
}
public void setFirstName(String name)
{
firstName = name;
}
public String getMiddleInitial()
{
return middleInitial;
}
public void setMiddleInitial(String midInit)
{
middleInitial = midInit;
}
public String getLastName()
{
return lastName;
}
public void setLastName(String ln)
{
lastName = ln;
}
/*
public sys.Login getLogin()
{
return login;
}
public void setLogin(sys.Login log)
{
login = log;
}
*/
public org.matesweb.shared.Group[] getGroups()
{
return groups;
}
public void setGroups(org.matesweb.shared.Group[] gro)
{
groups = gro;
}
public org.matesweb.shared.Purchase[] getPurchases()
{
return purchases;
}
public void setPurchases(org.matesweb.shared.Purchase[] purch)
{
purchases = purch;
}
}
Service
package org.matesweb.client;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import org.matesweb.shared.Person;
#RemoteServiceRelativePath("peopleService")
public interface PeopleService extends RemoteService {
//test services
String stringTest(String outgoingString);
Person getPerson(String persId);
//production services
String savePerson(Person p);
}
ServiceAsync
import com.google.gwt.user.client.rpc.AsyncCallback;
import org.matesweb.shared.Person;
public interface PeopleServiceAsync
{
//tests
void stringTest(String outgoingString, AsyncCallback<String> incomingString);
void getPerson(String persId, AsyncCallback<Person> retPerson);
//production services
void savePerson(Person p , AsyncCallback<String> st);
}
ServiceImpl call for this particular method:
//production calls
#Override
public String savePerson(Person p) {
String st = ioObj.saveObj(p);
if(st.equals("Success")){
return "Your information has been saved successfully!";
} else{
return "Something has gone wrong on our end... Sorry! Error:<br /> " + st;
}
}
and finally, the call itself
private static void savePerson(Person p)
{
// Initialize the service proxy.
if (peopleSvc == null) {
peopleSvc = GWT.create(PeopleService.class);
}
//resets status
st="";
// Set up the callback object.
AsyncCallback<String> callback = new AsyncCallback<String>() {
#Override
public void onFailure(Throwable caught) {
st = caught.getMessage();
Label stLabel= new Label(st);
personTable.setWidget(3,1,stLabel);
}
#Override
public void onSuccess(String result) {
st = result;
HTML stLabel= new HTML(st);
joinPanel.add(stLabel);
}
};
// Make the call to the people service.
peopleSvc.savePerson(p, callback);
}
I was able to fix this issue by implementing GWT's IsSerializable interface. I also removed the Serializable interface from the Person class and let it inherit IsSerializable from the abstract class it inherits from.