Using Jaxb Marshalling how can I override the XML Element names at runtime - spring

In my code I have a class which is populated from a REST CALL like so:
RestTemplate restTemplate = new RestTemplate();
String JSONStr = restTemplate.getForObject(urlStr, String.class);
Gson gson = new Gson();
Products items = gson.fromJson(JSONStr, Products.class);
Then later I write the the list as XML
JAXBContext jaxbContext = JAXBContext.newInstance(ProductsList.class);
Marshaller productMarshaller2 = jaxbContext.createMarshaller();
productMarshaller2.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
OutputStream outputStream = new FileOutputStream("xml\\products.xml");
for (int index = 0; index < items.size(); index++){
System.out.println("Index = " + index);
ProductsList productList = items.get(index);
productMarshaller2.marshal(productList, outputStream);
}
outputStream.close();
This all works great and provides the expected output. The problem I have is that the JSON that I get has field names like "atr_203948" and I need to place them with names like "color" - but can not know the mapping between the names ahead of time. At runtime I have to execute a DB lookup to get the current map. The DB look up is easy and I have code that creates a HashMap with the oldName,newName pairs but I do not know inject that knowledge into the output of the Marshaller. Any help would be greatly appreciated.

Related

MessageBodyWriter not found for media type=application/octet-stream, type=class org.apache.poi.xssf.usermodel.XSSFWorkbook

I have the below class that tries to return some data in the form of an excel spreadsheet. I'm getting the error
MessageBodyWriter not found for media type=application/octet-stream, type=class org.apache.poi.xssf.usermodel.XSSFWorkbook
I've also tried #Produces("application/vnd.ms-excel"), but have gotten similar errors. Anyone have a suggestion as to how I can get this to return a spreadsheet? The last time I got an error message similar to this (complaining that a message body writer couldn't be found for arraylist) I just wrapped it in a generic entity. That trick didn't work this time.
#PermitAll
#Path("uploadWorkbook")
public class ExcelUploadResource {
#Context
ResourceContext resourceContext;
#Inject
JobService jobService;
#GET
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response list() {
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("Job definitions");
int rowNum = 0;
for(Job job : jobService.list()){
Row row = sheet.createRow(rowNum++);
int cellNum = 0;
for(String field : job.toList()){
Cell cell = row.createCell(cellNum++);
cell.setCellValue(field);
}
}
GenericEntity<XSSFWorkbook> entity = new GenericEntity<XSSFWorkbook>(workbook) {};
ResponseBuilder response = Response.ok(entity);
response.header("Content-Disposition",
"attachment; filename=jobs.xls");
return response.build();
}
}
You can't just use arbitrary objects with the data type application/octet-stream. What you first need to understand is how objects are serialized. This is done with the use of MessageBodyWriters. You can learn more about them in JAX-RS Entity Providers.
How the writer works is that it is passed the entity and the response stream. The writer is supposed to take the entity and write the contents of the entity to the response stream. The writers are looked up by the type of entity we return and the media type expected, in your case you want it to be application/octet-stream.
What the error is saying is that there is no writer to handle the conversion of your XSSFWorkbook. When you talk about application/octet-stream, you're mostly dealing with binary files. XSSFWorkbook is not a binary file. When working with application/octet-stream, you'll mostly be working with byte[], File, InputStream, and StreamingOutput entity types. So if you want to use application/octet-stream, then you would need to change the entity to be one of those types.
I've never used Apache POI, but just going through a quick tutorial, it looks like what you probably want to use for this case is the StreamingOutput, you can just use the XSSFWorkbook#write(OutputStream) method to write the workbook to the StreamingOutput
public Response getExcelFile() {
XSSFWorkbook workbook = new XSSFWorkbook();
...
StreamingOutput output = new StreamingOutput() {
#Override
public void write(OutputStream out)
throws IOException, WebApplicationException {
workbook.write(out);
out.flush();
}
};
return Response.ok(output)
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=jobs.xls")
.build();
}

accessing Apache camel header in spring expression language

I want to access camel exchange header value while parsing spring expression.
1.
Is it possible ? I am looking some thing like below.
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("request.headers['myHeader'].concat('!')");
String message = (String) exp.getValue();
System.out.println(message);
or can we use #Header and access the same ?
Is there any other way than adding the value to StandardEvaluationContext as variable and then parsing the same ?
Appreciate some quick help on the same.
2.
One more question is is there a way i can register all my custom functions at only one place ? I mean i want to avoid registering functions for every call to evaluate the expression. Currently i am doing it below way.
public static String evalExpr(String expr,
Map<String, Object> variables) throws NoSuchMethodException,
SecurityException {
StandardEvaluationContext context = new StandardEvaluationContext();
context.registerFunction("concat", CusExprs.class
.getDeclaredMethod("concat", String[].class));
context.registerFunction("substr", CustExprs.class
.getDeclaredMethod("substr", new Class[] { String.class,
Integer.class, Integer.class }));
context.setVariables(variables);
return parser.parseExpression(expr).getValue(context, String.class);
}

Spring Rest Template to send JsonArray

I am using spring rest template to send json array as request. Source code to send request is as follow:
JSONArray jsonArray = new JSONArray();
for (Iterator iterator = itemlist.iterator(); iterator.hasNext();) {
Item item = (Item)iterator.next();
JSONObject formDetailsJson = new JSONObject();
formDetailsJson.put("id", item.getItemConfId());
formDetailsJson.put("name", item.getItems().getItemName());
formDetailsJson.put("price", item.getPrice());
formDetailsJson.put("Cost",item.getCost());
jsonArray.put(formDetailsJson);
}
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.APPLICATION_JSON);
// Prepare header
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
// Pass the new person and header
HttpEntity<JSONArray> entity = new HttpEntity<JSONArray>(jsonArray, headers);
System.out.println("Json Object : "+entity);
// Send the request as POST
try {
ResponseEntity<String> result = restTemplate.exchange("my url", HttpMethod.POST, entity, String.class);
} catch (Exception e) {
logger.error(e);
return "Connection not avilable please try again";
}
And to accept request:
#RequestMapping(value = "/testStock", method = RequestMethod.POST,headers="Accept=application/xml, application/json")
public #ResponseBody int testStock(#RequestBody List<ItemList> jsonArray) {
logger.debug("Received request to connect ms access : "+jsonArray.size());
//int returnSizecount = stockList.getStocklst().size();
return 1;
}
The problem is that it giving me following error:
Could not write request: no suitable HttpMessageConverter found for request type [org.json.JSONArray].Any suggestion is greatly acceptable.
There are no MessageConverter for JSONArray, so I suggest do the following.
HttpEntity<JSONArray> entity = new HttpEntity<JSONArray>(jsonArray, headers);
Convert Class JSONArray to String, and add that to HttpEntity, you know use toString
java.lang.String toString()
Make a JSON text of this JSONArray.
HttpEntity entity = new HttpEntity(jsonArray.toString(), headers);
Or change to Jackson implementation Spring have support to that. XD
If you dont want to do the above, consider create your own implementation of messageConverter, that will work but is harder
update
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
headers.setContentType(MediaType.APPLICATION_JSON);
update 2 Change endpoint to.
#RequestMapping(value = "/testStock", method = RequestMethod.POST)
public #ResponseBody int testStock(#RequestBody String jsonArray) {
you need to have httpmessageconverter configured for your resttemplate, please read my post for configuring http message conveter for you webservice
http://stackoverflow.com/questions/19963127/new-to-spring-and-jackson-2-what-does-this-bean-declaration-allow-for-in-a-spri/19973636#19973636.
and for you problem to convert your http request to json you might add this entry in your restemplate configuration
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
The error is quite straightforward. You do not have a converter for the JSONArray. Converting the array to a String (using toString) did help you here, but there is a better way:
Just add a converter for the json.org objects:
Add this to your pom.xml
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-json-org</artifactId>
</dependency>
And then on your ObjectMapper add the JsonOrgModule:
mapper.registerModule(new JsonOrgModule());

Using Spring RESTTeample how do I pass hashmap values for url on post?

Using Spring RESTTeample how do I pass hashmap values for url on post?
I am trying to use Spring RESTTeample to post a User Object to a web service but the issue I am having is that I am putting my id into a hashMap and I dont know how to pass the hashmap into RESTTemplate to use. Can you please look at the following code and let me know.. I dont want to hard code the ID on the URL
Map<String, String> vars = new HashMap<String, String>();
vars.put("id", "MMS");
RestTemplate rt = new RestTemplate();
rt.getMessageConverters().add(new MappingJacksonHttpMessageConverter());
rt.getMessageConverters().add(new StringHttpMessageConverter());
URI uri = new URI("http://" + mRESTServer.getHost() + ":8080/springmvc-resttemplate-test/api/{id}");
User u = new User();
u.setName("Mickey Mouse");
u.setUser("MMS");
User returns = rt.postForObject(uri, u, User.class);
In the code given, you are currently only passing the user information. If you want to pass the id and the user information to the REST service, why not put the user object into the hashmap along with the id and pass the hashmap to the rest service. A sample will be like this
Map<String, Object> request = new HashMap<String, Object>();
request.put("id", "MMS");
request.put("user", user);
restTemplate.postForObject(completeUrl,request, User.class);
This is provided your rest service accepts such an input.

Post data using Spring RestTemplate

I am trying to post data using Spring RestTemplate as below:
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
parameters.add("name1", "value1");
parameters.add("name2", "value2");
HttpMessageConverter<String> stringConverter = new StringHttpMessageConverter();
FormHttpMessageConverter formConverter = new FormHttpMessageConverter();
List<HttpMessageConverter<?>> msgConverters = new ArrayList<HttpMessageConverter<?>>();
msgConverters.add(formConverter);
msgConverters.add(stringConverter);
restTemplate.setMessageConverters(msgConverters);
String xml = restTemplate.postForObject(myurl, parameters, String.class);
On the server part, I am using a simple servlet to handle request as follow:
String name1 = request.getParameter("name1");
The server returns the xml as String.
When I used HashMap instead of MultiValueMap without Converter, the parameters are null on the server side. But after using the above code, I am getting error
Cannot extract response: no Content-Type found
Can you plz provide me a simple example to achieve what I want.
Here is what I used to format data for the Spring POST:
//FormHttpMessageConverter
is used to construct form parameters to POST on the URI
HttpMessageConverter<?> formHttpMessageConverter = new FormHttpMessageConverter();
HttpMessageConverter<?> stringHttpMessageConverter = new StringHttpMessageConverter();
List<HttpMessageConverter> msgConverters = new ArrayList<HttpMessageConverter>();
msgConverters.add(formHttpMessageConverter);
msgConverters.add(stringHttpMessageConverter);
// Prepare acceptable media type
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.ALL);
// Prepare header
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
HttpEntity<MultiValueMap<String,String>> httpEntity = new HttpEntity<MultiValueMap<String,String>>(map,headers);
ResponseEntity<String> resp = restTemplate.exchange("https://risk.XXXX.XXXXXX.net",HttpMethod.POST,httpEntity,String.class);

Resources