Empty uri in rest response - rest

I am developing a plugin for nexus oss .My app creates a rest call response(to a request from server) . But when the server receives it , it throws error as follows
javax.xml.bind.UnmarshalException:
unexpected element (uri:"", local:"com.collabnet.teamforge.ia.types.GetConfigurationParametersResponse").
Expected elements are
\lt{http://www.collab.net/teamforge/integratedapp}CreateProjectConfigurationRequest\gt,
\lt{http://www.collab.net/teamforge/integratedapp}GetConfigurationParametersRequest\gt,
\lt{http://www.collab.net/teamforge/integratedapp}GetConfigurationParametersResponse\gt,
\lt{http://www.collab.net/teamforge/integratedapp}GetPageComponentParametersRequest>
I guess the reason behind this exception is that the response doesn't match with the expected because the uri ( this is just my guess , if it's wrong please correct me),that is the namespace in response is not set .
snip of the Code in my plugin is as follows
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"configurationParameter"
})
#XmlRootElement(name = "GetConfigurationParametersResponse", namespace = "http://www.collab.net/teamforge/integratedapp")
public class GetConfigurationParametersResponse
extends BaseResponse
{
Why is name space not picked up while creating response ?
Even correct me if the real reason for the exception is not the empty uri. If so what is the real reason behind this exception ?
Please help .

Based on the error message the XML document being passed to JAXB is. It appears as though this XML is being created by something other than JAXB (I suspect XStream).
<com.collabnet.teamforge.ia.types.GetConfigurationParametersResponse>
...
</com.collabnet.teamforge.ia.types.GetConfigurationParametersResponse>
Your JAXB mappings are expecting an XML document like the following:
<GetConfigurationParametersResponse xmlns="http://www.collab.net/teamforge/integratedapp">
...
</GetConfigurationParametersResponse>
If you need to interact with the following XML:
<com.collabnet.teamforge.ia.types.GetConfigurationParametersResponse>
...
</com.collabnet.teamforge.ia.types.GetConfigurationParametersResponse>
Then you can change your mapping to be:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"configurationParameter"
})
#XmlRootElement(name = "com.collabnet.teamforge.ia.types.GetConfigurationParametersResponse")
public class GetConfigurationParametersResponse
extends BaseResponse
{

Related

How JAXB mapping is done in Spring boot SOAP webservices

I have a question on JAXB mapping using org.springframework.ws.server.endpoint.annotations.
I was able to generate Java domain object with provided *.xsd. The thing is after I define my endpoint with
#PayloadRoot, I have to wrap my request and response as below to successfully trigger the method and return a result:
#PayloadRoot( localPart = "PmtAuthAddRequest",
namespace = "http://*com/emb/webseries")
#ResponsePayload
public JAXBElement billPayment(#RequestPayload JAXBElement var1){
PmtAuthAddResponseType response=billPaymentHandler.execute(var1.getValue());
return of.createPmtAuthAddResponse(response); // Used ObjectFactory to create JAXBElement.
}`
`
From all the tutorial I see, they dont need to wrap it as JAXBElement to return the correct type, but the below code does not work for me:
`
`#PayloadRoot( localPart = "PmtAuthAddRequest",
namespace = "http://*com/emb/webseries")
#ResponsePayload
public PmtAuthAddResponseType billPayment(#RequestPayload PmtAuthAddRequestType> var1){
PmtAuthAddResponseType response=billPaymentHandler.execute(var1.getValue());
return response;
}`
`
Do you guys know why? How can I resolve this? Thanks
I tried without wrapping it as JAXBElement, but soap UI return with error message:
`no adapter for endpoint [public com.*.*.*.webseries.billpay.CustPayee50InqResponseType com.*.Endpoint.InquirePayeeEndpoint.inquirepayees(com.*.*.*.webseries.billpay.CustPayee50InqRequestType) throws javax.xml.bind.JAXBException]: Is your endpoint annotated with #Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?</faultstring>
`
Actually solved my own question....
The way to do it is to add #XmlRootElement under generated Java class from JAXB2 with below to correctly mapping:
#XmlRootElement(namespace = "http://..*/emb/webseries",name = "CustPayee50InqRequest")
The name should match with the localPart provided name from #PayloadRoot.
Added both for request and response makes it work for me

Spring boot add error message to rest response without throwing exception but keeping typed response

My REST endpoints return ResponseEntity<SomeDto> or only SomeDto. Out of this i generating swagger to be consumed by front end. Of course the type information SomeDto is crucial.
Within my endpoint methods i am doing some basic checks to prevent exception further down the road (fail as fast as possible).
Returning ResponseEntity.badRequest().build() in such cases works fine, but i want to add a error message to the body. But adding a String to the body is not possible in regards to ResponseEntity<SomeDto>.
Question
How i can add a error message while maintaining the signature/ contract without the need of raising an exception (see "Effective Java 3rd edition - "Item 69: Use exceptions only for exceptional conditions")?
one (bad) way i see is to add an error message field to all my dtos (could be specified by an interface).
You don't need to add error model to individual object instead extend Response model from Base class which has error definition defined, this is how i would implement it.
static abstract class ApiResponse {
enum Status {
SUCCESS,
FAILURE,
}
#Getter
#Setter
private Status status;
#Getter
#Setter
private String errorMessage;
}
class NamesDto extends ApiResponse {
#Setter
#Getter
String[] names;
}
#GetMapping(value = "namesdto")
public ResponseEntity<ApiResponse> getNames() {
final NamesDto namesDto = new NamesDto();
namesDto.setStatus(ApiResponse.Status.FAILURE);
namesDto.names = new String[]{"john", "doe"};
return ResponseEntity.ok(namesDto);
}
#GetMapping(value = "errordto")
public ResponseEntity<ApiResponse> erroDto() {
final NamesDto namesDto = new NamesDto();
namesDto.setErrorMessage("No names found");
namesDto.setStatus(ApiResponse.Status.FAILURE);
return ResponseEntity.ok(namesDto);
}
#Getter/#Setter are imports from import lombok.* package
Either using ResponseEntity.badRequest().body(xxx).build() or throwing an exception is fine, as soon as the contract is the same.
You are using a lib to generate a Swagger Doc (such as Springfox) ? Well, it does fine for some situations but it can't perform miracles. The documentation generation should not affect how you write your code. In such a case, #ApiResponse is what you need.

Customising Spring Boot Exception Handling to Prevent Stacktraces Being Returned in Rest Response

How do I configure my spring boot service so that errors such as 500 don't potentially leak implementation details such as stacktraces.
{
"timestamp": "2019/05/01 15:06:17",
"status": 500,
"error": "Internal Server Error",
"message": "Type definition error: [simple type, class net.i2p.crypto.eddsa.math.ed25519.Ed25519LittleEndianEncoding]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class net.i2p.crypto.eddsa.math.ed25519.Ed25519LittleEndianEncoding and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.Collections$UnmodifiableRandomAccessList[0]->........)",
"path": "/api/test"
}
Note: here the stacktrace is in the message and not the exception part of the json.
As you can see I am already formatting the timestamp with:
#Component
public class CustomErrorAttributes extends DefaultErrorAttributes {
private static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
private static final String TIMESTAMP = "timestamp";
#Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
//Let Spring handle the error first
Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
//Format & update timestamp
Object timestamp = errorAttributes.get(TIMESTAMP);
if(timestamp == null) {
errorAttributes.put(TIMESTAMP, dateFormat.format(new Date()));
} else {
errorAttributes.put(TIMESTAMP, dateFormat.format((Date)timestamp));
}
return errorAttributes;
}
}
But I need to handle the message too.
If this 500 was the only error I could just do:
errorAttributes.put("message", "Server error. Contact support.");
However, all the errors go through here and that would override all the messages.
I could check if the status is 500 and only modify it then. However, there are other errors that can be generated that also might leak stacktraces.
Using #RestControllerAdvice seems to require knowing every exception that is generated and having an #ExceptionHandler for each and knowing which status code to respond with.
Is there a cleaner way to handle this?
It may not be the "cleanest" approach, but with projects I've been on we had a "standard format" for our Error Responses across projects, so we had a custom object with the fields that matched our orgs standard (HttpStatus, Reason, ect.) that extended RuntimeException. Then in our controllers, services, repos, ect we would catch exceptions and create this object accordingly and throw the custom one up instead. Based upon where it happened in the app (repo, service, controller, ect.) we could give our own custom verbage to it, but still log out the full exception in our server logs so we could investigate later
For example if we caught an error in our repository we would create our custom error object, set the Reason to DB unavailable (really all the consumer needs to know), set the status to HttpStatus.SERVICE_UNAVAILABLE (we tracked these with reasons and httpstatus with enums to keep status the same across modules), and throw the custom object up to the controller to be returned.
Sorry if this was a longwinded answer that may not give you what you want, I'm not too familiar with how you're trying to do it so figured I'd just give an example of other methods. I'll put some sample code as well
Custom Exception:
data class MyException(
val reason: String,
val httpStatus: HttpStatus? = null
) : RuntimeException(reason)
Method for creation:
fun createApiException(errorCode: ErrorCodeEnum) = MyException(
reason = errorCode.reason,
httpStatus = errorCode.httpStatus,
)
Spring-boot provides us with a standard method to handle exceptions using spring aop concept. You can use the #ControllerAdvice and #Exceptionhandled annotations to handle exceptions from a spring-boot rest endpoint so that a custom exception is always thrown from a rest endpoint with proper error code and error response.
The #ResponseStatus() annotation can be used to customize the response code being thrown.
For example consider the custom exception :
#ResponseStatus(HttpStatus.NOT_FOUND)
public class DataNotFoundException extends RuntimeException {
public DataNotFoundException(String exception) {
super(exception);
}
}
We can throw this error from a rest GET mapping when a data is not found like :
#GetMapping("/trains/{id}")
public Resource<Student> retrieveTrains(#PathVariable long id) {
Optional<Trains> trains = trainRepository.findById(id);
if (!train.isPresent())
throw new DataNotFoundException("id-" + id);
Resource<Trains> resource = new Resource<Trains>(train.get());
ControllerLinkBuilder linkTo = linkTo(methodOn(this.getClass()).retrieveAllTrains());
resource.add(linkTo.withRel("all-trains"));
return resource;
}
Default error response provided by Spring Boot contains all the details that are typically needed.
However, you might want to create a framework independent response structure for your organization. In that case, you can define a specific error response structure.
For example :
public class ErrorDetails {
private Date timestamp;
private String message;
private String details;
public ErrorDetails(Date timestamp, String message, String details) {
super();
this.timestamp = timestamp;
this.message = message;
this.details = details;
}
To use this error node we use :
#ControllerAdvice
public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(DataNotFoundException.class)
public final ResponseEntity<ErrorDetails> handleUserNotFoundException(DataNotFoundException ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(),
request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
}
#ExceptionHandler(DataNotFoundException.class) indicates that this
method would handle exceptions of the specific type.
new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND) - Create an
error response object and return it with a specific Http Status.
For a more generalized exception handler you can define a method that handles exception of the type Exception.class, that way you don't have to know every exception.
Like :
#ExceptionHandler(Exception.class)
public final ResponseEntity<ErrorDetails> handleAllExceptions(Exception ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(),
request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
}
Reference from : https://www.javaguides.net/2019/02/spring-boot-2-angular-7-crud-example-tutorial.html

Error resolving template - url mapping fails

I receive the following error message:
Error resolving template [catalog/getCatalogItemFromCatalog/catalogItemId/3916677], template might not exist or might not be accessible by any of the configured Template Resolvers
I am trying to reach my service and the method using this url:
http://192.168.99.100:31003/catalog/getCatalogItemFromCatalog/catalogItemId/3916677
Controller:
#Controller
#RequestMapping("catalog")
public class CatalogController {
#GetMapping("/getCatalogItemFromCatalog/catalogItemId/{catalogItemId}")
public CatalogItem getCatalogItemFromCatalog(#PathVariable Integer catalogItemId){
List<Catalog> catalogs = getAllCatalogs();
Optional<CatalogItem> optionalCatalogItem = Optional.empty();
for(Catalog catalog : catalogs){
optionalCatalogItem = catalog.getCatalogItems().stream().filter(it -> it.getCatalogItemId().equals(catalogItemId)).findFirst();
}
return optionalCatalogItem.orElse(null);
}
#GetMapping("/system/ipaddr")
public String getIpAddr() {
List<String> response;
response = runSystemCommandAndGetResponse(IP_ADDR);
return new Gson().toJson(response);
}
}
When I curl
http://192.168.99.100:31003/catalog/system/ipaddr
I have no issues.
I am testing for hours now and nothing seems to work, I have no idea why its failing tho.
you have #Controller on your class which means spring will try to resolve the return type of all your methods inside the controller using all the available templateResolvers.
by using #ResponseBody spring will wrap the return type inside the response (after converting it) directly then returns it to the client, it's similar to using #RestController instead #Controller

jersey 2.0 jaxrs RI - return json string on exception

I am creating a REST service using jersey 2.0. I am extending WebApplicationException
Method raising a particular exception
if(json.equals("") || json.equals(" ")) {
throw new ArgumentException("bad post data");
}
public class ArgumentException extends RestException {
.....
public ArgumentException(String message) {
super(Status.BAD_REQUEST,message);
}
}
public class RestException extends WebApplicationException {
...........
public RestException(Status status, String message) {
super(Response.status(status)
.entity(message)
.type("text/plain")
.build());
/*
super(Response.status(status)
.entity(new ErrorBean(status.getStatusCode(),message))
.type(MediaType.APPLICATION_JSON)
.build()); */
}
ErrorBean is a POJO
The method that returns error as plain string inside RestException works (right http code 400 and message). However when I try to pass the ErrorBean POJO and use MediaType.APPLICATION_JSON in response I get an error saying "Headers have already been sent" with http error code 500 (so some internal problem with plumbing) and empty response.
I have also looked at this question Returning JSON or XML for Exceptions in Jersey
How can I return the exception with code and message as a JSON like
{"code" : 400, "message" : .... }
Update
I have received answer on SO as well as jersey users mailing list. steps are
A non AJXB POJO does not need any annotations
Register JacksonFeature in your application
ResourceConfig rc = new ResourceConfig().packages("test").register(JacksonFeature.class);
You need to register JacksonFeature in your Application/ResourceConfig, i.e.:
// Create JAX-RS application.
final Application application = new ResourceConfig()
.packages("org.glassfish.jersey.examples.jackson")
.register(JacksonFeature.class)
// No need to register this provider if no special configuration is required.
.register(MyObjectMapperProvider.class);
Take a look at the documentation for Jackson support in Jersey and also at the example.