How to pass parameter to controller to get the correct object in spring mvc - spring-mvc

I define an object like
public class DrivelogBean implements Serializable{
private String backInfoIdentify;
private DriVehNum driVehNum;
public static class TotalMileageIntd implements Serializable{
private static final long serialVersionUID = -3268743972404969523L;
private String totalMileage;
private String mileageTime;
public String getTotalMileage () {
return totalMileage;
}
public void setTotalMileage (String totalMileage) {
this.totalMileage = totalMileage;
}
public String getMileageTime () {
return mileageTime;
}
public void setMileageTime (String mileageTime) {
this.mileageTime = mileageTime;
}
}
}
and my controller is like:
#RequestMapping(value="saveDriveLog",method = RequestMethod.GET)
public #ResponseBody ResultBean saveDriveLog(DrivelogBean drivelogBean){
driveLogService.addDriveLog (drivelogBean);
ResultBean resultBean = new ResultBean();
resultBean.setRet (1);
resultBean.setDescripion (UsConstants.DRIVELOG_SAVE);
return resultBean;
}
I want request parameters convert to drivelogBean
and my url is like that:
http://127.0.0.1:8080//manage/drivelog/saveDriveLog/?backInfoIdentify=2&totalMileageIntd["driverNum%22]=1&totalMileageIntd["driveCode"]=2
but the page prompt
HTTP ERROR: 404 Problem accessing //manage/drivelog/saveDriveLog/error. Reason:Not Found
and i change the url like :
http://127.0.0.1:8080//manage/drivelog/saveDriveLog/?commendWord=2&totalMileageIntd.driverNum=1&totalMileageIntd.driveCode=2
but the drivelogBean parameter, the property driverNum of totalMileageIntd and the property driveCode of totalMileageIntd is null.
So how can I set the correct url pass parameter to the drivelogBean?

I don't know if binding inner static class works in spring.
Your parametter must match a setter
commendWord=2 => you must have setCommendWord on the class DrivelogBean
totalMileageIntd.driverNum=1 => you must have a setDriverNum() on and a getTotalMileageIntd
The class should look like this (I skipped getter and setter to save space but they must exists)
public class DrivelogBean implements Serializable{
private String backInfoIdentify;
private DriVehNum driVehNum;
private TotalMileageIntd totalMileageIntd ;
public static class TotalMileageIntd implements Serializable{
private static final long serialVersionUID = -3268743972404969523L;
private String totalMileage;
private String mileageTime;
}
}
In this case all the parametter you can use are :
backInfoIdentify=XXX
driVehNum=XXX
totalMileageIntd.totalMileage=XXX
totalMileageIntd.mileageTime=XXX
nothing else

Related

Unable to Mock the Database call handled by Spring JPA framework while writing test Case for Controller Class

Spring MVC converts the id from path to corresponding object by making call to JpaRepository's findById method. For example see getVersionTree() method.
public class Controller {
#NonNull
private final MyService service;
#NonNull
private final MyAssembler assembler;
#GetMapping(path = VERSION_TREE_MAPPING, produces = MediaTypes.HAL_JSON_UTF8_VALUE)
public HttpEntity<?> getVersionTree(#PathVariable("id") MappingDocument mappingDocument, Pageable pageable, PagedResourcesAssembler<VersionNode> pagedResourcesAssembler) {
Page<VersionNode> versionNodes = service.getVersionTreeFor(mappingDocument, pageable);
return new ResponseEntity<>(pagedResources, HttpStatus.OK);
}
While testing, SpringMVC throws " Failed to convert value of type 'java.lang.String' to required type 'com.rbc.dna.dtl.mappingdocument.MappingDocument'". I am mocking jpaRepository.findById() method. Test Code is as follows:
#Autowired
private WebApplicationContext webApplicationContext;
#MockBean
private MyRepository repository;
#Mock
MyController controller;
#MockBean
private MyServiceImpl serviceImpl;
#Test
public void testMethod() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).apply(SecurityMockMvcConfigurers.springSecurity()).build();
MappingDocument mappingDocumentl=MappingDocument.builder().id(17L).build();
Mockito.when(repository.findById(17L)).thenReturn(Optional.of(mappingDocumentl));
Mockito.when(serviceImpl.getVersionTreeFor(mappingDocument,pageable)).thenReturn(pagedResponse);
mockMvc.perform(MockMvcRequestBuilders.get("/abc/17/def").param("page","0").param("size","20").contentType(MediaTypes.HAL_JSON_UTF8_VALUE)
.with(authentication(getOauthTestAuthentication()))
.sessionAttr("scopedTarget.oauth2ClientContext", getOauth2ClientContext()))
.andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print());
}
Your rest Controller take #PathVariable("id") MappingDocument mappingDocument as variable in your path, but in mockMvc.perform you are passing a simple String/Number or something that doesn't bind with MappingDocument.
Try to replace
public HttpEntity<?> getVersionTree(#PathVariable("id") MappingDocument mappingDocument...
with
public HttpEntity<?> getVersionTree(#PathVariable("id") Long idMappingDocument, ...
If you want to keep your object in #PathVariable you need to change
#GetMapping(path = VERSION_TREE_MAPPING)
To parse an object as PathVariable you need to have path that represent property of your object.
For example if you have
class Person {
String name;
String address;
//getters and setters
}
and you need to define a controller as follow:
#GetMapping(path = "/person/{name}/{address}", produces = MediaTypes.HAL_JSON_UTF8_VALUE)
public HttpEntity<?> getVersionTree(Person person) {
Where {name} and {address} must bind Person properties

On Save, the foreign key value in child table is empty for REST XML service

This is a REST XML service. On Save, the foreign key value in child table is empty.
The #Id's are using sequence and it works fine. Im not added the sequence generator code here.
//Main Entity
------------
#Entity
#Table(name="REQUEST")
public class MsaDisabScreenRequest implements Serializable {
#Id
#Column(name="REQUEST_ID")
private long requestId; //sequence
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE }, fetch = FetchType.LAZY, mappedBy="msaDisabScreenRequest")
private Set<ReqDetail> disabilities;
}
Child Entity
#Entity
#Table(name="REQ_DETAILS")
public class ReqDetail implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="MAP_ID")
private long mapId; //sequence
#Column(name="TYPE_ID")
private long disabilityTypeId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="REQUEST_ID")
privateRequest msaDisabScreenRequest;
}
This is the dto that I'm using to map.
//Main Dto
#XmlRootElement(name="DisabilityRequest")
#XmlAccessorType(XmlAccessType.FIELD)
public class MsaDisabScreenRequestDto implements Serializable {
private static final long serialVersionUID = 1L;
private long requestId;
#NotNull
private Set<DetailDto> disabilities;
}
//Child Dto
#XmlRootElement(name="disabilities")
#XmlAccessorType(XmlAccessType.FIELD)
public class MsaDisabScreenReqDetailDto implements Serializable {
private static final long serialVersionUID = 1L;
private long mapId;
private long disabilityTypeId;
#XmlTransient
private RequestDto msaDisabScreenRequest;
}
This is the controller
#RequestMapping(value = ApiPath.REQUEST, method = RequestMethod.POST, produces = { "application/xml"})
public #ResponseBody ResultDecorator saveScreeningRequest(#Valid #RequestBody RequestDto requestDto) throws Exception {
.
.
.
.
}
save code which is using jpa repository to persist.
Implementation code only added the code releavant to save
#Autowired
private OrikaBeanMapper mapper;
.
.
.
.
.
.
.
// mapping
Request request = mapper.map(requestDto,Request.class);
Request Res = msaRepository.save(request);
This is the request payload I'm sending
<?xml version="1.0" encoding="UTF-8" ?>
<DisabilityRequest>
<disabilities>
<disabilityTypeId>9</disabilityTypeId>
</disabilities>
</DisabilityRequest>
Here the requestId is added as empty REQ_DETAILS table. All other entries passed are persisted.
Let me know if you need any further details.
When fetch type is LAZY, the data set are empty. You can use Fetch type EAGER but its expensive

how to get the values from properties file in the test cases

I am getting null while reading the values from .properties file when i am executing the test case. here while debugging the test case i am able to see the values which are loaded from properties file when the curser is there in the test class but when the curser enters into the actual class in that class i am getting the same values as null. And my code is as follows
Thanks in advance
#RestController
#PropertySource("classpath:/com/example/prop.properties")
public class ReadProp {
#Value("${name}")
private String name;
#Value("${rollNo}")
private String rollNo;
#RequestMapping(value="/")
public void getDetails(){
System.out.println(name);
System.out.println(rollNo);
}
}
and the test case is as follows
#RunWith(SpringRunner.class)
#SpringBootTest
#PropertySource("classpath:/com/example/prop.properties")
public class ReadPropTest {
private ReadProp readProp = new ReadProp();
#Value("${name}")
private String name;
#Value("${rollNo}")
private String rollNo;
#Test
public void readValues() {
System.out.println(name);
System.out.println(rollNo);
readProp.getDetails();
}
}
Instead of creating a new object using new ReadProp(). You should Autowire it.
#Autowired
ReadProp readProp;
in your test class. If you create an object using new, you don't get the bean which spring created with all the value assigned using #Value.
Try something like this :
#PropertySource("classpath:prop.properties")// your error
public class ReadPropTest {
#Value("${name}")
private String name;
#Value("${rollNo}")
private String rollNo;
}

Curiosities in deserializing collections with gson 2

I have these classes
public class Application {
public String name;
public String ico;
public List<MenuStruct> menu =new ArrayList<MenuStruct>();
//Constructor
public Application() { }
}
public class MenuStruct {
public String id;
public String type;
public String parent;
public String name;
public String secId;
//Constructor
public MenuStruct() {}
}
If I try to deserialize a collection directly in this way:
ApplicationManager apm= new ApplicationManager();
s="[ {\"name\":\"reg_salida\" , \"ico\":\"document-open-2-32x32.ico\" }]";
apm.apps=(new Gson()).fromJson(s,apm.apps.getClass() );
for (Application ap:apm.apps){
System.out.println(ap.name); //gets error here
}
I get a java.lang.ClassCastException.
But if I try to deserialize its containig class ApplicationManager it does not fail.
s="{ \"apps\": [ {\"name\":\"reg_salida\" , \"ico\":\"document-open-2-32x32.ico\" }]}";
ApplicationManager apm=(new Gson()).fromJson(s,ApplicationManager.class);
for (Application ap:apm.apps){
System.out.println(ap.name); // now no errors here! and shows reg_salida
}
Is this a bug of gson 2.2.4? or maybe I am doing something not correct?
Eduard.
You have to provide full definition of property class. Your example should looks like that:
manager.apps = gson.fromJson(json, new TypeToken<List<Application>>() {}.getType());

Adobe Flex Builder WSDL classes autogenerator generates weird files

Adobe Flex Builder WSDL classes autogenerator generates wierd files.
For example:
http://ws.cdyne.com/WeatherWS/Weather.asmx?wsdl
After importing it generates these files:
ArrayOfForecast.as
ArrayOfWeatherDescription.as
ArrayOfWeatherDescription0.as
BaseWeather.as
BaseWeatherSchema.as
Forecast.as
ForecastReturn.as
ForecastReturn0.as
GetCityForecastByZIPResultEvent.as
GetCityForecastByZIP_request.as
GetCityWeatherByZIPResultEvent.as
GetCityWeatherByZIP_request.as
GetWeatherInformationResultEvent.as
GetWeatherInformation_request.as
IWeather.as
POP.as
Temp.as
Weather.as
WeatherDescription.as
WeatherReturn.as
WeatherReturn0.as
What are these ZERO at the end files for?
That was an example for service with 3 operations. My real wsdl has much more methods and types.
UPDATED
At the same time Java generates much cleaner set of classes:
Forecast.java
ForecastReturn.java
POP.java
Temp.java
WeatherDescription.java
Weather.java
WeatherLocator.java
WeatherReturn.java
WeatherSoap12Stub.java
WeatherSoap.java
WeatherSoapProxy.java
WeatherSoapStub.java
It's not noticeable for such small service, but for bigger service with more operations and types it generates hundreds of classes. I have doubt that Adobe Flex team does wsdl classes autogeneration in proper way.
UPDATE-2
WeatherReturn.as:
public class WeatherReturn
{
/**
* Constructor, initializes the type class
*/
public function WeatherReturn() {}
public var Success:Boolean;
public var ResponseText:String;
public var State:String;
public var City:String;
public var WeatherStationCity:String;
public var WeatherID:Number;
public var Description:String;
public var Temperature:String;
public var RelativeHumidity:String;
public var Wind:String;
public var Pressure:String;
public var Visibility:String;
public var WindChill:String;
public var Remarks:String;
}
WeatherReturn0.as:
public class WeatherReturn0
{
/**
* Constructor, initializes the type class
*/
public function WeatherReturn0() {}
public var WeatherReturn:com.cdyne.WeatherReturn;
}
WeatherReturn.java:
public class WeatherReturn implements java.io.Serializable {
private boolean success;
private java.lang.String responseText;
private java.lang.String state;
private java.lang.String city;
private java.lang.String weatherStationCity;
private short weatherID;
private java.lang.String description;
private java.lang.String temperature;
private java.lang.String relativeHumidity;
private java.lang.String wind;
private java.lang.String pressure;
private java.lang.String visibility;
private java.lang.String windChill;
private java.lang.String remarks;
// Skipped constructors and getter/setter
private java.lang.Object __equalsCalc = null;
public synchronized boolean equals(java.lang.Object obj)
private boolean __hashCodeCalc = false;
public synchronized int hashCode()
// Type metadata
private static org.apache.axis.description.TypeDesc typeDesc = new org.apache.axis.description.TypeDesc(WeatherReturn.class, true);
static {
typeDesc.setXmlType(new javax.xml.namespace.QName("http://ws.cdyne.com/WeatherWS/", "WeatherReturn"));
org.apache.axis.description.ElementDesc elemField = new org.apache.axis.description.ElementDesc();
elemField.setFieldName("success");
elemField.setXmlName(new javax.xml.namespace.QName("http://ws.cdyne.com/WeatherWS/", "Success"));
elemField.setXmlType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "boolean"));
elemField.setNillable(false);
typeDesc.addFieldDesc(elemField);
elemField = new org.apache.axis.description.ElementDesc();
elemField.setFieldName("responseText");
// More typedesc here ...
}
public static org.apache.axis.description.TypeDesc getTypeDesc() {
public static org.apache.axis.encoding.Serializer getSerializer(
public static org.apache.axis.encoding.Deserializer getDeserializer(
}
I left only methods signatures for Java example and skipped getters/setters.

Resources