Spring RestController ignore XmlElement annotation in Wrapper Class - spring

I'm using Spring 4.x and I have following RestController method which should return list of all flights
#RequestMapping(produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}, method = RequestMethod.GET)
public FlightWrapper returnAllFlights() {
List<FlightDto> flights = data.findAll();
return new FlightWrapper(flights);
}
FlightWrapper class looks like this (rootElement = flights element = flight):
#XmlRootElement(name = "flights")
public class FlightWrapper {
private List<FlightDto> flights;
public FlightWrapper() {}
public FlightWrapper(List<FlightDto> flights) {
this.flights = flights;
}
#XmlElement(name = "flight")
public List<FlightDto> getFlights() {
return flights;
}
public void setFlights(List<FlightDto> flights) {
this.flights = flights;
}
}
The problem is when I call returnAllFlights() it will return xml in this format:
<FlightWrapper>
<flights>
<flights>
....
</flights>
<flights>
....
</flights>
</flights>
</FlightWrapper>
I expected that single flight should have tag flight and whole list of flights should be flights however as you can see items in list have the same tag as list itself.
Any idea how to fix it ?

According with your comments since you are using jackson-dataformat-xml module the JAXB annotations now are ignored. You must update your class to use these annotations.
#JacksonXmlRootElement(localName="flights")
public class FlightWrapper {
private List<FlightDto> flights;
public FlightWrapper() {}
public FlightWrapper(List<FlightDto> flights) {
this.flights = flights;
}
#JacksonXmlElementWrapper(useWrapping=false)
#JacksonXmlProperty(localName="flight")
public List<FlightDto> getFlights() {
return flights;
}
public void setFlights(List<FlightDto> flights) {
this.flights = flights;
}
}
I had the same problem than you but through Spring Framework, not through Spring Boot. But that behaviour happens when the jackson-dataformat-xml module is added into the classpath. It according with my experience.

Related

Sending #Value annotated fields to a DTO layer returns null

I have a class which is composed of 2 different objects :
public class MyClass{
private OptionClass optionClass;
private ConstantClass constantClass;
public DocumentToSignRestRequest(OptionClass optionClass, ConstantClass constantClass) {
this.optionClass= optionClass;
this.constantClass= constantClass;
}
}
My first class is a classic POJO. My second class retrieve values from the application.properties file.
public class ConstantClass {
#Value("${api.url}")
private String hostName;
#Value("${sign.path}")
private String pathStart;
public ConstantClass () {
this.hostName= getHostName();
this.path = getPath();
}
I map MyClass with MyClassDto in order to call a service.
#PostMapping(
value="/sign",
consumes = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE },
produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE }
)
public MyClassRest prepareDocument(#RequestBody DocumentToPrepare documentToPrepare) throws Exception {
MyClassRest returnValue = new MyClassRest ();
ModelMapper modelMapper = new ModelMapper();
MyClassDto myClassDto = modelMapper.map(documentToPrepare, MyClassDto .class);
DocumentDto signedDocument = documentService.signDocument(documentDto);
returnValue = modelMapper.map(signedDocument, DocumentRest.class);
return returnValue;
}
My DTO class work fine and retrieve the OptionClass datas, but concerning the second Class, i obtain null as value, while i try to print it out in the service layer.
Your ConstantClass should be a Bean or a Component (as #cassiomolin says in comments)
#Component
public class ConstantClass {
private String hostName;
private String pathStart;
public ConstantClass (#Value("${api.url}") String url, #Value("${sign.path}") String path ) {
this.hostName = url;
this.pathStart = path;
}
// getters...
Then you can easily inject this component in your Controller and use it.
#Controller
public class YourController(){
private ConstantClass constantClass;
public YourController(ConstantClass constantClass){
this.constantClass = constantClass;
}
#PostMapping("...")
public MyClass post(.....){
.....
MyClass myclass = new MyClass(this.constantClass,...)
.....
}
}
note that Spring can autowire #Value and #Component, ... via the constructor; that can be very useful when you do unit-testing

How can I load propeties in a Map with SpringBoot?

I try to initialize a Map in my SpringBoot application but I am doing something wrong.
My config.properties:
myFieldMap.10000.fieldName=MyFieldName
myFieldMap.10000.fieldName2=MyFieldName2
myFieldMap.10001.fieldName=MyFieldName
myFieldMap.10001.fieldName2=MyFieldName2
myFieldMap.10002.fieldName=MyFieldName
myFieldMap.10003.fieldName2=MyFieldName2
...
(Isn't it possible to use some kind of bracket notation like myFieldMap[10001].fieldName for maps (I saw it used for lists).
I tried with my MyConfig.class:
#PropertySource("classpath:config.properties")
#Component
public class MyConfig {
private java.util.Map<Integer, MyMapping> theMappingsMap = new HashMap<Integer, MyMapping>();
public Map<String, MyMapping> getTheMappingsMap() {
return theMappingsMap;
}
public void setTheMappingsMap(Map<String, MyMapping> theMappingsMap) {
this.theMappingsMap= theMappingsMap;
}
public class MyMapping {
private String fieldName;
private String fieldName2;
public String getFieldName() {
return fieldName;
}
public String getFieldName2() {
return fieldName2;
}
public void setFieldName(final String fieldName) {
this.fieldName = fieldName;
}
public void setFieldName2(final String fieldName) {
this.fieldName2 = fieldName;
}
}
}
How do I have to adapt my code to let SpringBoot initialize my configuration (Map) with the definitions in the config.properties file?
You are missing #ConfigurationProperties annotation. Try this
#PropertySource("classpath:config.properties")
#Configuration
#ConfigurationProperties
public class MyConfig {
private java.util.Map<String, MyMapping> myFieldMap = new HashMap<>();
....
}
Another issue with your code is, if you want to make MyMapping class as an inner class of MyConfig, then you need to declare it as static. Or else you can make it as a separate class.

Spring Boot YML Config Class Inheritance

Is it possible to use inheritance in Spring Boot YML configuration classes? If so, how would that be accomplished?
For example:
#ConfigurationProperties(prefix="my-config")
public class Config {
List<Vehicle> vehicles;
}
And the class (or interface) "Vehicle" has two implementations: Truck and Car. So the YAML might look like:
my.config.vehicles:
-
type: car
seats: 3
-
type: truck
axles: 3
I do not think it is possible (at least not that I know of). You could however design your code as follow:
Inject the properties into a Builder object
Define an object with all properties, which we'll call the VehicleBuilder (or factory, you choose its name).
The VehicleBuilders are injected from the Yaml.
You can then retrieve each builder's vehicle in a #PostConstruct block. The code:
#ConfigurationProperties(prefix="my-config")
#Component
public class Config {
private List<VehicleBuilder> vehicles = new ArrayList<VehicleBuilder>();
private List<Vehicle> concreteVehicles;
public List<VehicleBuilder> getVehicles() {
return vehicles;
}
public List<Vehicle> getConcreteVehicles() {
return concreteVehicles;
}
#PostConstruct
protected void postConstruct(){
concreteVehicles = vehicles.stream().map(f -> f.get())
.collect(Collectors.<Vehicle>toList());
}
}
The builder:
public class VehicleBuilder {
private String type;
private int seats;
private int axles;
public Vehicle get() {
if ("car".equals(type)) {
return new Car(seats);
} else if ("truck".equals(type)) {
return new Trunk(axles);
}
throw new AssertionError();
}
public void setType(String type) {
this.type = type;
}
public void setSeats(int seats) {
this.seats = seats;
}
public void setAxles(int axles) {
this.axles = axles;
}
}

Unitest by using mockito(one class is dependent with other scenario)

Hi I am very new to mocking framework. Can any one please help me to write a junit by using any mocking framework. Below is my requirement
I wanted to write a unitest for getListOfEmp method by using mock with expected value.
Note Here I am facing difficulty to mock EmpValue class to get the accurate value in ServiceClass
public class ServiceClass {
public Employe getListOfEmp(List<String> criteria) {
Employe emp = new Employe();
EmpValue empValue = new EmpValue();
if (criteria.contains("IT")) {
emp.setEid(empValue.getIt());
}
if (criteria.contains("SALES")) {
emp.setEid(empValue.getSales());
}
if (criteria.contains("SERVICE")) {
emp.setEid(empValue.getService());
}
return emp;
}
}
public class EmpValue {
private String it = "IT-1001";
private String service = "SERVICE-1001";
private String sales = "SALES-1001";
public String getIt() {
return it;
}
public String getService() {
return service;
}
public String getSales() {
return sales;
}
}
First I will do some changes to the code to make it testable.
1: EmplValue object should be passed to the method by the client or should be an instance variable in your Service class. Here I am using it as an instance variable, so that client can set it.
public class ServiceClass {
private EmpValue empValue;
public ServiceClass(EmpValue empValue){
this.empValue = empValue;
}
public Employe getListOfEmp(List<String> criteria) {
Employe emp = new Employe();
if (criteria.contains("IT")) {
emp.setEid(empValue.getIt());
}
if (criteria.contains("SALES")) {
emp.setEid(empValue.getSales());
}
if (criteria.contains("SERVICE")) {
emp.setEid(empValue.getService());
}
return emp;
}
}
I am using Mockito and JUnit to write unit-test for this class .
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
#RunsWith(MockitoJunitRunner.class)
public class ServiceClassTest{
#Test
public void shouldReturnEmployeeWithEidSetWhenCriteriaIsIT(){
// Craete mock and define its behaviour
EmpValue mEmpValue = mock(EmpValue.class);
when(mEmpValue.getIt()).thenReturn("IT-1001");
// Create the object of class user test with mock agent and invoke
ServiceClass serviceClass = new ServiceClass(mEnpValue);
Employee result = serviceClass.getListOfEmp(asList("IT"));
// Verify the result as per your expectation
assertEquals("It-001", result.getEid());
}
}

smartgwt listgrid RestDataSource not populating

Im new using this front end framework application...
I recently started to work with smartgwt and i'm bulding a new application with a Spring MVC integration.
I'm using a ListGrid with a RestDataSource (Consume the Rest service with mvc:annotation-driven for plain JSON)
I can see that the servaice gets consuming properly perhaps my grid is never shown with the data in it.
Can someone help me here ?
Here's my ListGrid class
public class ListGrid extends com.smartgwt.client.widgets.grid.ListGrid {
private final SpringJSONDataSource springJSONDataSource;
public ListGrid(List<DataSourceField> fields) {
this(new PatientDataSource(fields));
}
public ListGrid(SpringJSONDataSource springJSONDataSource) {
this.springJSONDataSource = springJSONDataSource;
init();
}
private void init() {
setAutoFetchData(true);
setAlternateRecordStyles(true);
setEmptyCellValue("???");
setDataPageSize(50);
setDataSource(springJSONDataSource);
}
}
Now there's the DataSource implmentation
public abstract class SpringJSONDataSource extends RestDataSource {
protected final HTTPMethod httpMethod;
public SpringJSONDataSource(List<DataSourceField> fields) {
this(fields, HTTPMethod.POST);
}
public SpringJSONDataSource(List<DataSourceField> fields, HTTPMethod httpMethod) {
this.httpMethod = httpMethod;
setDataFormat(DSDataFormat.JSON);
addDataSourceFields(fields);
setOperationBindings(getFetch());
addURLs();
}
private void addURLs() {
if(getUpdateDataURL() != null)
setUpdateDataURL(getUpdateDataURL());
if(getRemoveDataURL() != null)
setRemoveDataURL(getRemoveDataURL());
if(getAddDataURL() != null)
setAddDataURL(getAddDataURL());
if(getFetchDataURL() != null)
setFetchDataURL(getFetchDataURL());
}
private void addDataSourceFields(List<DataSourceField> fields) {
for (DataSourceField dataSourceField : fields) {
addField(dataSourceField);
}
}
protected abstract OperationBinding getFetch();
protected abstract OperationBinding getRemove();
protected abstract OperationBinding getAdd();
protected abstract OperationBinding getUpdate();
public abstract String getUpdateDataURL();
public abstract String getRemoveDataURL();
public abstract String getAddDataURL();
public abstract String getFetchDataURL();
}
The class PatientDataSource that extends SpringJSONDataSource
public class PatientDataSource extends SpringJSONDataSource {
public PatientDataSource(List<DataSourceField> fields) {
super(fields);
setPrettyPrintJSON(true);
}
#Override
protected OperationBinding getFetch() {
OperationBinding fetch = new OperationBinding();
fetch.setOperationType(DSOperationType.FETCH);
fetch.setDataProtocol(DSProtocol.POSTMESSAGE);
DSRequest fetchProps = new DSRequest();
fetchProps.setHttpMethod(httpMethod.toString());
fetch.setRequestProperties(fetchProps);
return fetch;
}
#Override
public String getFetchDataURL() {
return "/spring/fetchPatients";
}
#Override
protected OperationBinding getRemove() {
return null;
}
#Override
public String getRemoveDataURL() {
return null;
}
#Override
protected OperationBinding getAdd() {
return null;
}
#Override
public String getAddDataURL() {
return null;
}
#Override
protected OperationBinding getUpdate() {
return null;
}
#Override
public String getUpdateDataURL() {
return null;
}
}
My spring controller PatientControler
#Controller
public class PatienController {
Logger logger = Logger.getLogger(PatienController.class);
#Autowired
private PatientServices patientServices;
#RequestMapping(value = "/patientTest", method = RequestMethod.GET)
#ResponseBody
public Object getTest()
{
return patientServices.getAllPatients();
}
#RequestMapping(value = "/fetchPatients", method = RequestMethod.POST)
#ResponseBody
public Object getAllPatients()
{
return patientServices.getAllPatients();
}
}
PatientServiceImpl
public class PatientServicesImpl implements PatientServices {
public List<Patient> getAllPatients() {
List<Patient> patients = new ArrayList<Patient>();
Patient patient;
for(int i = 0 ; i < 500 ; i++){
patient = new Patient();
patient.setDateOfBirth(new Date());
patient.setFirstName("Joe");
patient.setMiddleName("Moe");
patient.setLastName("Blow");
patient.setLastConsultation(new Date());
patient.setSex(Sex.M);
patients.add(patient);
}
return patients;
}
}
*Im Really stuck right now i've been looking for all type of answers .... but so far nothing worked when i tried to override the transformResponse from my RestDataSource impentation the parameter "data" as an OBJECT, returns me an array [object Object],[object Object],[object Object],[object Object],[object Object] *
The Data which is transferred from the RestDataSource has a specific format which is described in the JavaDoc of the RestDataSource
Your server must understand the request and send back a valid response.
At the moment your example doesn't seem to honour the contract.
To debug the traffic send to and from your server you can use the SmartClient-Console. You can open it by a browser bookmark like this:
javascript:isc.showConsole()
Of cause you need to deploy this console by adding the following module to your gwt.xml
<inherits name="com.smartclient.tools.SmartClientTools"/>
Now go to the RPC Tab and check Track-RPCs

Resources