RestEasy - Unable to find MessageBodyReader ... application/xml? - wildfly

i try since 2 days to find something about this problem, still don't get it. I got my Maven-Project running on Wildfly.
Rest-Code:
#Override
#GET
#Path("{id}")
// #Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Customer getOverId(#PathParam("id") String id) {
logger.info("put in " + this.getClass().getName() + " over id " + id);
// if (id != null) {
// Customer object = service.loadOneCustomer(new Integer(id));
// logger.info("found in " + this.getClass().getName());
// return Response.ok(object).build();
// }
Customer customer = service.loadOneCustomer(new Integer(id));
// logger.info("nix found");
if(customer == null) {
throw new NotFoundException("No customer found with the matching ID: " + id);
}
logger.info("Customer found: " + customer.getCustomerNumber());
// return Response.status(Status.BAD_REQUEST).build();
return customer;
}
Client-Implementation:
public Response readCustomer(String id){
log.info("Starting: Rest get a Customer with ID: " + id);
log.info(this.URL);
this.customerWebTarget = this.client.target(this.URL).path(id);
Response response = this.customerWebTarget.request().buildGet().invoke();
// TODO Customer cast application_xml auf Customer? Customer customer = response.readEntity(Customer.class);
Customer customer = response.readEntity(Customer.class);
log.info("Ending: Rest invoque a Customer with ID:" + customer.getCustomerNumber());
// System.out.println("Ending: Rest get a Customer with ID: " + response.readEntity(String.class));
return response;
}
J-Unit Test:
#Test
public void testGetCustomerById() throws Exception {
Response response = this.customerRestClient.readCustomer("112");
System.out.println("--->" + response.getStatus());
Assert.assertTrue(response.getStatus() == 200);
}
Everything works perfekt till i try to get the Java-Object from the XML i get (Customer customer = response.readEntity(Customer.class);)
Am i missing something. I mean, i get read the xml-File and see every data in it... Why can't i cast it into Java-Object?
I always get this Error:
Javax.ws.rs.ProcessingException: Unable to find a MEssageBody of content-type-application/xml and type class de.....model.Customer

Without seeing the Customer class, it's hard to tell, but most likely some or all JAXB annotations are missing. In particular, you'll need an #XmlRootElement annotation.

Can you post the Customer class please. Was it properly annotated?
Also add the #Produces back in.

Related

returning a value using REST

I am getting errors when I am trying to return values using REST. The error is:
A HTTP GET method, public - should not consume any entity.
This is my class:
public class StockManagement {
ArrayList<String> items = new ArrayList<>();
ArrayList<Integer> stockLevel = new ArrayList<>();
#GET
#Produces("application/xml")
public String addItem(String item) {
if(items.contains(item)) { // returns true is item is exists else false
String r = "Item is already in list";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>"+ "<div>" + result + "</div>" +"</StockManagementService>";
}
else {
String r = "Item has been added successfully";
String result = "#Produces(\"application/xml\")" + r;
items.add(item); // add item to inventory
stockLevel.add(0); // set the number of stock for the item in inventory
return "<StockManagementService>" +"<div>" + result + "</div>" +"</StockManagementService>";
}
}
#GET
#Produces("application/xml")
public String setStock(String item, int stockLevels) {
if(!items.contains(item)) {
String r = "Item is not in the inventory";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>" + result + "</StockManagementService>";
}
else {
int index = items.indexOf(item);
stockLevel.set(index, stockLevels);
String r = "Set stock has been complete successfully";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>" + result + "</StockManagementService>";
}
}
#GET
#Produces("application/xml")
public String addStock(String item, int numItem) {
if(!items.contains(item)) {
String r = "Error, Cannot add item";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>" + result + "</StockManagementService>";
}
else {
int index = items.indexOf(item);
String r = "Successfully added stock";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>" + result + "</StockManagementService>";
}
}
#GET
#Produces("application/xml")
public String removeStock(String item, int numItem) {
if(items.contains(item)) {
int index = items.indexOf(item);
int val = stockLevel.get(index);
val = val - numItem;
stockLevel.set(index, val);
String r = "Successfully removed item.";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>" + result + "</StockManagementService>";
}
else {
String r = "Item is not in the inventory";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>" + result + "</StockManagementService>";
}
}
This is the error shown on eclipse terminal:
SEVERE: The following errors and warnings have been detected with resource and/or provider classes:
WARNING: A HTTP GET method, public java.lang.String com.crunchify.restjersey.StockManagement.setStock(java.lang.String,int), should not consume any entity.
WARNING: A HTTP GET method, public java.lang.String com.crunchify.restjersey.StockManagement.addStock(java.lang.String,int), should not consume any entity.
WARNING: A HTTP GET method, public java.lang.String com.crunchify.restjersey.StockManagement.removeStock(java.lang.String,int), should not consume any entity.
WARNING: A HTTP GET method, public java.lang.String com.crunchify.restjersey.StockManagement.addItem(java.lang.String), should not consume any entity.
SEVERE: Consuming media type conflict. The resource methods public java.lang.String com.crunchify.restjersey.StockManagement.addStock(java.lang.String,int) and public java.lang.String com.crunchify.restjersey.StockManagement.setStock(java.lang.String,int) can consume the same media type
SEVERE: Consuming media type conflict. The resource methods public java.lang.String com.crunchify.restjersey.StockManagement.removeStock(java.lang.String,int) and public java.lang.String com.crunchify.restjersey.StockManagement.setStock(java.lang.String,int) can consume the same media type
SEVERE: Consuming media type conflict. The resource methods public java.lang.String com.crunchify.restjersey.StockManagement.addItem(java.lang.String) and public java.lang.String com.crunchify.restjersey.StockManagement.setStock(java.lang.String,int) can consume the same media type
I cannot figure out what this error means, obviously it has to be the way I am returning, any help would be appreciated.
Thanks.
No promises, but I think the WARNING is trying to remind you that, in HTTP, GET doesn't take a message body. So String item should probably be encoded into the URI itself, which might mean a #QueryParam or #PathParam annotation.
SEVERE is trying to tell you that there are multiple methods that are all trying to be mapped to the same route. That is to say, they are all mapped to the same URI with the same method and the same application type, so how is the routing logic supposed to choose between them.
That might mean that you need to specify different paths for each, or that you should have only one annotated method that has the logic to choose which implementation to use.

What should my repository return on a http post when the posted id (foreign key) is wrong

Given the user sends a valid token to an api endpoint via fiddler/postman, he could post a resource (pupil) for a related resource (schoolclass).
When the schoolclass id
does not exist yet in the database
does exist already in the database but this schoolclass Id belongs to another user.
does exist in the database and belongs to the passed userId
Then
What would you change in the Controller and Repository class to make it work for all 3 cases using a REST api + repository pattern.
Controller:
[HttpPost("~/api/pupils")]
public async Task<IActionResult> Post([FromBody]CreatePupilRequestDto dto)
{
var userId = User.GetUserId();
var pupil = dto.ToPupil();
await repository.CreatePupil(pupil, dto.SchoolclassId, userId);
return Ok(pupil.Id);
}
Repository:
public async Task CreatePupil(Pupil pupil, int schoolclassCodeId, string userId)
{
var schoolclassCode = await context.Schoolclasses.SingleOrDefaultAsync(s => s.Id == schoolclassCodeId && s.UserId == userId);
if (schoolclassCode != null)
{
schoolclassCode.Pupils.Add(pupil);
await context.SaveChangesAsync();
}
}
NOTE
At the moment the last of the 3 use cases is implemented!
From REST prospective you need to return 400 or 404 depending on your design.
If your route need to be like /classes/{id}/users/{id}/pupil I thing you need to use 404 in case user or class is wrong.
In case of separate route (as I can see in your question) I think this should be 400 code as request URL is pointing to valid resource but payload is invalid.
In both cases I think the batter error handling strategy here is to write some set of custom exceptions (like EntityNotFondException, EntityInvalidException, BusinessLogicException) and throw them from repository in case something is wrong. Then you can create some global action filter or OWIN middleware to catch those exceptions and translate them to correct response status codes with appropriate messages
Example:
public class NotFoundException : Exception
{
public NotFoundException(Type entityType)
: base($"Entity {entityType.Name} was not found")
{
}
}
public class ApiExceptionFilterAttribute : ExceptionFilterAttribute
{
public ApiExceptionFilterAttribute()
{
}
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
var exception = actionExecutedContext.Exception;
if (exception == null)
return;
if (exception is HttpResponseException)
return;
var entityNotFoundException = exception as NotFoundException;
if (entityNotFoundException != null)
{
actionExecutedContext.Response = actionExecutedContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, entityNotFoundException.Message);
return;
}
}
}
Usage:
var schoolclassCode = await context.Schoolclasses.SingleOrDefaultAsync(s => s.Id == schoolclassCodeId && s.UserId == userId);
if(schoolclassCode == null)
throw new NotFoundException(typeof(Schoolclass));
You can throw validation exceptions in the same way. E.g:
var schoolclassCode = await context.Schoolclasses.SingleOrDefaultAsync(s => s.Id == schoolclassCodeId);
if(schoolclassCode == null)
throw new InvalidModelStateException("Schoolclass was not found.")
if(schoolclassCode.UserId != userId)
throw new InvalidModelStateException("Schoolclass is owned by different user.")
... etc.
I always use Result classes for returning state from a service class (wouldn't implement that in Repository as it shouldn't contain business logic):
public class QueryResult
{
private static readonly QueryResult success = new QueryResult { Succeeded = true };
private readonly List<QueryError> errors = new List<QueryError>();
public static QueryResult Success { get { return success; } }
public bool Succeeded { get; protected set; }
public IEnumerable<QueryError> Errors { get { return errors; } }
public static QueryResult Failed(params QueryError[] errors)
{
var result = new QueryResult { Succeeded = false };
if (errors != null)
{
result.errors.AddRange(errors);
}
return result;
}
}
public class QueryResult<T> : QueryResult where T : class
{
public T Result { get; protected set; }
public static QueryResult<T> Suceeded(T result)
{
if (result == null)
throw new ArgumentNullException(nameof(result));
var queryResult = new QueryResult<T>
{
Succeeded = true,
Result = result
};
return queryResult;
}
}
public class QueryError
{
public string ErrorId { get; set; }
public string ErrorMessage { get; set; }
}
And use it like
var schoolclassCode = await context.Schoolclasses
.SingleOrDefaultAsync(s => s.Id == schoolclassCodeId && s.UserId == userId);
if (schoolclassCode == null)
return QueryResult.Failed(new QueryError
{
ErrorId = 1,
ErrorMessage = "Invalid User Id"
});
Edit:
Just as an addition and rule of thumb
Services which operate on one or multiple entities and perform user input validation should return Result classes
Domain Models (which you don't seem to use, since you use a repository and Repository + Rich Domains doesn't work out well in real life applications) should throw exception (i.e. InvalidOperationException or ArgumentException, ArgumentNullException). Doing Result-types her will pollute the model and mix the separation of responsibility (Domain Model will suddenly also do validation instead only guarding against invalid state)
Using XxxResult type classes gives you an easy way to transport one or multiple errors back to the user, where an exception should act as an guard against your domain model getting into invalid state.
Edit 2
In response to the comments:
public async Task<IActionResult> Post([FromBody]CreatePupilRequestDto dto)
{
var userId = User.GetUserId();
var pupil = dto.ToPupil();
var result = await repository.CreatePupil(pupil, dto.SchoolclassId, userId);
// If you want to suppress the error messages, just call return BadRequest() instead
if(!result.Succeeded)
return BadRequest(result.Errors);
return Ok(pupil.Id);
}
Edit 3
Example with 3 parameters for let's say /api/schoolclasses/1/students/2/lessons/2 (Update an existing lesson to the student with the id 2 for the school class with id 1).
// on SchoolClasses Controller
[HttpPost("{schoolClassId:int}/students/{studentId:int}/lessons/{lessonId:int}")]
public async Task<IActionResult> Post([FromBody]Lessons lessonDto)
{
// rough input validation, do first to avoid db hits
if(!ModelState.IsValid)
return BadRequest(ModelState);
// best put logic into service classes i.e. SchoolClassService
var result = schoolClassService.UpdateLessonFor(schoolClassId, studentId, lessonDto)
// If you want to suppress the error messages, just call return BadRequest() instead
if(!result.Succeeded)
return BadRequest(result.Errors);
return Ok();
}
Content of UpdateLessonsFor
List<ErrorMessage> errors = new List<ErrorMessage>();
// with .Include to include both student and all of his lessons
// does student exist?
// Hits db once and gets both, student and all lessons in a single query
var student = _context.SchoolClasses
.Include(sc => sc.Students)
.ThenInclude(s => s.Lessons)
.Where(sc => sc.SchoolClassId == schoolClassId)
.SelectMany(sc => sc.Students)
FirstOrDefault(s => s.StudentId == studentId);
if(student==null)
return QueryResult.Failed( new ErrorMessage { ErrorId = 1, ErrorMessage = "Student or School Class not found" } );
// Doesn't hit the database, since lessons have been loaded with the above call
var lesson = student.Lessons.Any(l => l.LessonId = lessonId))
if(lesson == null)
return QueryResult.Failed( new ErrorMessage { ErrorId = 2, ErrorMessage = "Lesson not found. " } );
// modify it
lesson.SomeValue = dto.SomeValue;
try
{
} catch(Exception ex) {
return QueryResult.Failed(new ErrorMessage { ErrorId = 3, ErrorMessage = "Couldn't update the lesson. Try again and if the error appears again, contact the administrator." } );
} finally {
return QueryResult.Suceeded;
// or if you also want to return a result
return QueryResult.Suceeded(lesson);
}
Also from the comments of the other answer: Don't put logic into your repository, that's what services are for when you use anemic domain (models have no logic, all in services) or have thin service layer and put most logic into domain service. But that's out of the scope.

How to restrict to a list of query params for a REST api

I want to restrict to a set of query params for rest Method.
#Path("/users")
public class UserService {
#GET
#Path("/query")
public Response getUsers(
#QueryParam("from") int from,
#QueryParam("to") int to,
#QueryParam("orderBy") List<String> orderBy) {
return Response
.status(200)
.entity("getUsers is called, from : " + from + ", to : " + to
+ ", orderBy" + orderBy.toString()).build();
}
}
“users/query?from=100&to=200&orderBy=age&orderBy=name” [WORKS]
“users/query?x=y” [also works and when my query params are set with default values]
i want throw some exceptions based on that.

ResponseEntity Spring MVC

What is the best way to return an error message with ReponseEntity?
Say I have the following method
#Transactional
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<User> getUser(#PathVariable("id") Long id) {
User user = userRepository.findOne(id);
if (user == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
else {
return new ResponseEntity<>(user, HttpStatus.OK);
}
Now what if I want to return an error message to the front end? I can't do the following because the method return type is
ResponseEntity<User>
not
ResponseEntity<String>
so this will not work
if (user == null) {
return new ResponseEntity<>("User does not exist", HttpStatus.NOT_FOUND);
}
I could make the method return type
ResponseEntity<Object>
but that just seems slopy and bad practice. I want to be able to return at least a brief error message that gives some indication of what went wrong to the front end. How is the best way to go about doing this?
Update:
After some digging around I came up with this and it seems to work but curious if it would have a performance impact.
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<?> getUser(#PathVariable("id") Long id) {
User user = userRepository.findOne(id);
if (user == null) {
return new ResponseEntity<>("User not found", HttpStatus.NOT_FOUND);
}
else {
return new ResponseEntity<>(user, HttpStatus.OK);
}
}
I realise you asked specifically about returning the error message using ReponseEntity, but you could also consider using Spring MVCs exception handling to acheive the same outcome:
// Example from the linked Spring article:
#RequestMapping(value="/orders/{id}", method=GET)
public String showOrder(#PathVariable("id") long id, Model model) {
Order order = orderRepository.findOrderById(id);
if (order == null) throw new OrderNotFoundException(id);
model.addAttribute(order);
return "orderDetail";
}
#ResponseStatus(value=HttpStatus.NOT_FOUND, reason="No such Order") // 404
public class OrderNotFoundException extends RuntimeException {
// ...
}

How to retrieve all the Groups/Roles a user is member of using SOAP services?

I am trying to collect some user informations using SOAP services.
I was able to get the Job Title for a given user, but I don't understand how to retrieve the list of groups and roles that a user has.
Can I simply use the GroupServiceSoap.getUserPlaces(long userId, String[] classNames, int max) method? Or is there another way I can get these fields?
Currently my code:
private static URL _getURL(String remoteUser, String password, String serviceName) {
final String LIFERAY_PROTOCOL = "http://";
final String LIFERAY_TCP_PORT = "8080";
final String LIFERAY_FQDN = "localhost";
final String LIFERAY_AXIS_PATH = "/api/secure/axis/";
try {
return new URL(LIFERAY_PROTOCOL + URLEncoder.encode(remoteUser, "UTF-8") + ":"
+ URLEncoder.encode(password, "UTF-8") + "#" + LIFERAY_FQDN
+ ":" + LIFERAY_TCP_PORT + LIFERAY_AXIS_PATH + serviceName);
} catch (MalformedURLException e) {
return null;
} catch (UnsupportedEncodingException e) {
return null;
}
}
[...]
public static void main(String[] argv){
public final String LIFERAY_USER_SERVICE="Portal_UserService";
public final String LIFERAY_COMPANY_SERVICE="Portal_CompanyService";
public final String LIFERAY_GROUP_SERVICE = "Portal_GroupService";
//company.default.web.id property
public final String LIFERAY_DEFAULT_COMPANY_ID = "liferay.com";
UserServiceSoap userService = new UserServiceSoapServiceLocator().getPortal_UserService(_getURL(USER_IDENTIFIER,USER_PASSWORD, LIFERAY_USER_SERVICE));
//This code is usefull if you want to use SOAP setter.
//((Portal_UserServiceSoapBindingStub) userService).setUsername(USER_IDENTIFIER);
//((Portal_UserServiceSoapBindingStub) userService).setPassword(USER_PASSWORD);
CompanyServiceSoap companyService = new CompanyServiceSoapServiceLocator().getPortal_CompanyService(_getURL(USER_IDENTIFIER, USER_PASSWORD, LIFERAY_COMPANY_SERVICE));
long companyId = companyService.getCompanyByMx(LIFERAY_DEFAULT_COMPANY_ID).getCompanyId();
// Here I retrieve my user, and can access some properties, but not them all !
UserSoap user = userService.getUserByEmailAddress(companyId, target_user_mail);
//TODO : I got hte JobTittle that I want, later I will do something more util thant just print it, I swear it my precious !
System.out.println(user.getJobTitle());
GroupServiceSoap groupService = new GroupServiceSoapServiceLocator().getPortal_GroupService(_getURL(USER_IDENTIFIER, USER_PASSWORD, LIFERAY_GROUP_SERVICE));
//this one return an empty array
GroupSoap[] userPlaces = groupService.getUserPlaces(new String[]{"Group", "Role"}, 150);
//this return an array of size 1, but the only GroupSoap seems to be a structural groups without any usefull properties to me.
GroupSoap[] userPlaces = groupService.getUserPlaces(null, 150);
}
Use this method to get user role and group user id
UserServiceSoap.getRoleUserIds
UserServiceSoap.getGroupUserIds
HTH
It is only a partial answer.
In order to get all the User Roles one can do this :
RoleServiceSoap roleService = new RoleServiceSoapServiceLocator().getPortal_RoleService(_getURL(USER_IDENTIFIER, USER_PASSWORD, LIFERAY_ROLE_SERVICE));
RoleSoap[] userRoles = roleService.getUserRoles(user.getUserId());
with user variable an instance of UserSoap.
The SOAP access must be done by an Admin user in order to get access to the Role List. The user can't access this himself.