Closed vebhhav closed 9 years ago
Yep that's true it is clearly stated in project documentation actually. And yep there is a big space for improvement here (for example there are Spring annotations that are also nice to cover)
Regards, Pavel
Thanks. How can we help you to get this fixed?
Regards -veb
Sent from my iPhone
On Mar 16, 2015, at 2:43 PM, petrochenko-pavel-a notifications@github.com wrote:
Yep that's true it is clearly stated in project documentation actually. And yep there is a big space for improvement here (for example there are Spring annotations that are also nice to cover)
Regards, Pavel
— Reply to this email directly or view it on GitHub.
It's not a matter of a fix (it isn't broken), it's a matter of adding new functionality, right? Just making sure I understand it.
On Tue, Mar 17, 2015 at 10:40 AM, vebhhav notifications@github.com wrote:
Thanks. How can we help you to get this fixed?
Regards -veb
Sent from my iPhone
On Mar 16, 2015, at 2:43 PM, petrochenko-pavel-a < notifications@github.com> wrote:
Yep that's true it is clearly stated in project documentation actually. And yep there is a big space for improvement here (for example there are Spring annotations that are also nice to cover)
Regards, Pavel
— Reply to this email directly or view it on GitHub.
— Reply to this email directly or view it on GitHub https://github.com/mulesoft/raml-for-jax-rs/issues/52#issuecomment-82357309 .
Hi @vebhhav, I am going to work on adding this functionality into the project. Do you have any examples of use-cases that I may use for testing of this feature. (I already have couple in my mind, but it would be nice to be sure that we are on same plate). I am mostly interested in your vision of how it should behave in the cases when we have code annotated both with jax-rs and swagger annotations.
Thanks in advance, Pavel
Hi @petrochenko-pavel-a, Connected to your response to Vebhav . Below is the behavior expectation on swagger annotation . @ApiResponses and @ApiResponse should be able to identify the model class mentioned in the annotation and generate the schema and sample instance (XML\JSON based on media type). @ApiResponses(value = { @ApiResponse(code=200, message="success", response=XYZ.class)
In case of JAX-RS when we give the request and response signature with JAX-B annotated model class it is generating the sample and schema instance which is good for requirement having less effort in making signature changes but for most of the case the best option we feel is to apply the request and response signature without making the change(update) on code which is by adding swagger annotation on existing code. Special Note: Observed that when using the JAX-B annotated model class , the annotation @xmlTransient is supposed to neglect the field during the schema or sample instance generation but could see that all the feilds irrepective of whether annotated with @xmltransient or @xmlelement is getting generated.
Thanks Arun
Hi @petrochenko-pavel-a,
PFB the JAX-RS service and associated JAX-B class for your testing
JAX-RS class
@Path("/employee")
public class MacService extends AbstractRestServiceHandler
protected UserService(MacBRestServiceProxy proxy, APIAccessController accessController) {
super(proxy, accessController);
responseBeanType = new TypeToken<ResponseBean<MacUser>>(){}.getType();
}
@GET
@Path("/{name}")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@AllowAccess(roles = {APIRole.END_USER, APIRole.GROUPADMIN})
@ApiResponses(value = { @ApiResponse(code=200, message="success", response=MacUser.class),
@ApiResponse(code=404, message="invalid user name")})
public Response getUser(@PathParam("name") String userId, @HeaderParam(API_KEY_HEADER_NAME)String restKey, @Context SecurityContext securityContext) {
try {
checkAccess(securityContext.getUserPrincipal().getName(), getRole(securityContext), userId);
}
catch (IllegalAccessException e) {
logger.error(e.getMessage(), e);
return Response.status(Response.Status.FORBIDDEN).entity(new ResponseBean<MacUser>(ApplicationErrorCodes.ACCESS_DENIED)).build();
}
return restServiceProxy.handleGet(InfraRequestMethod.GET_USER, userId, getResponseBeanType(), restKey, this);
}
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@ApiResponses(value = { @ApiResponse(code=200, message="success", response=MacUser.class)})
public Response listUsers(@HeaderParam(API_KEY_HEADER_NAME)String restKey) {
return restServiceProxy.handleGetList(InfraRequestMethod.GET_ALL_USERS, null, getResponseBeanType(), restKey, this);
}
@POST
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@ApiResponses(value = { @ApiResponse(code=200, message="success", response=MacUser.class),
@ApiResponse(code=400, message="User already exists")})
public Response addUser(MacUser clientUser, @HeaderParam(API_KEY_HEADER_NAME)String restKey) {
return restServiceProxy.handlePost(InfraRequestMethod.ADD_USER, clientUser, "name", restKey, this);
}
@DELETE
@Path("/{contractorname}")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@ApiResponses(value = { @ApiResponse(code=200, message="success", response=MacDUser.class),
@ApiResponse(code=400, message="failed to delete user"),
@ApiResponse(code=409, message="user can not be deleted")})
public Response deleteUser(@PathParam("contractorname") String userId, @HeaderParam(API_KEY_HEADER_NAME)String restKey) {
return restServiceProxy.handleDelete(InfraRequestMethod.DELETE_USER, userId, restKey, this);
}
@PUT
@Path("/{name}")
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@AllowAccess(roles = {APIRole.END_USER, APIRole.GROUPADMIN})
@ApiResponses(value = { @ApiResponse(code=200, message="success", response=MacDUser.class),
@ApiResponse(code=400, message="fail to updated, invalid user")})
public Response modifyUser(MacUser userBeingModified, @HeaderParam(API_KEY_HEADER_NAME)String restKey,
@Context SecurityContext securityContext) {
try {
checkAccess(securityContext.getUserPrincipal().getName(), getRole(securityContext), userBeingModified.getname());
}
catch (IllegalAccessException e) {
logger.error(e.getMessage(), e);
return Response.status(Response.Status.FORBIDDEN).entity(new ResponseBean<MacUser>(ApplicationErrorCodes.ACCESS_DENIED)).build();
}
return restServiceProxy.handlePut(InfraRequestMethod.UPDATE_USER, userBeingModified, restKey, this);
}
/**
* Returns the instance of UserValidator
*
* @return
* @throws Exception
*/
@Override
public IValidator<MacUser> getRestValidatorInstance() throws Exception {
return UserValidator.class.newInstance();
}
}
JAX-B model class
@Relationships(values={"usergroup:/usergroups/{usergroup}"})
@XmlRootElement(name="users")
@XmlType(name="usersType")
@XmlAccessorType(XmlAccessType.FIELD)
public class MacUser{
private static final long serialVersionUID = -4679643118148992782L;
private static final String ADMIN = "admin222";
private static final String INFRA_USER = "infraUser222";
@Id
@XmlElement
@NotNull
private String username;
@JsonProperty("first_name")
@XmlElement(name="first_name")
@Max(value=256, message="Max supported length is 256 characters")
private String firstName;
@JsonProperty("last_name")
@Max(value=256, message="Max supported length is 256 characters")
@XmlElement(name="last_name")
private String lastName;
@XmlElement
private String email;
@XmlElement
private String address;
//@JsonProperty("phone_number")
@XmlElement(name="phone_number")
private String phoneNumber;
@XmlTransient
private String password;
@XmlElement
private String role;
@XmlElement
private String usergroup;
//@JsonProperty("system_user")
@XmlElement(name="system_user")
private boolean systemUser;
//@JsonProperty("restricted_user")
@XmlElement(name="restricted_user")
private boolean restrictedUser;
// boolean fields to check what field is set from client
@XmlTransient
private boolean isUserNameSet;
@XmlTransient
private boolean isFirstNameSet;
@XmlTransient
private boolean isLastNameSet;
@XmlTransient
private boolean isEmailSet;
@XmlTransient
private boolean isAddressSet;
@XmlTransient
private boolean isPhoneNumberSet;
@XmlTransient
private boolean isPasswordSet;
@XmlTransient
private boolean isUserRoleSet;
@XmlTransient
private boolean isUserGroupSet;
public MacUser() {
super();
}
public MacUser(String userId) {
super();
this.username = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
setUserNameSet(Boolean.TRUE);
if (StringUtils.isNotBlank(username)) {
if (username.equals(ADMIN)) {
setSystemUser(true);
setRestrictedUser(false);
} else if (username.equals(INFRA_USER)) {
setSystemUser(true);
setRestrictedUser(true);
} else {
setSystemUser(false);
setRestrictedUser(false);
}
}
}
public String getUsergroup() {
return usergroup;
}
public void setUsergroup(String userGrp) {
this.usergroup = userGrp;
setUserGroupSet(Boolean.TRUE);
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
setFirstNameSet(Boolean.TRUE);
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
setLastNameSet(Boolean.TRUE);
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
setEmailSet(Boolean.TRUE);
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
setAddressSet(Boolean.TRUE);
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
setPhoneNumberSet(Boolean.TRUE);
}
//@JsonIgnore
public String getPassword() {
return password;
}
//@JsonProperty
public void setPassword(String password) {
this.password = password;
setPasswordSet(Boolean.TRUE);
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
setUserRoleSet(Boolean.TRUE);
}
/**
* @return the isUserNameSet
*/
//@JsonIgnore
@XmlTransient
public boolean isUserNameSet() {
return isUserNameSet;
}
/**
* @param isUserNameSet
* the isUserNameSet to set
*/
@JsonProperty
public void setUserNameSet(boolean isUserNameSet) {
this.isUserNameSet = isUserNameSet;
}
/**
* @return the isFirstNameSet
*/
@JsonIgnore
public boolean isFirstNameSet() {
return isFirstNameSet;
}
/**
* @param isFirstNameSet
* the isFirstNameSet to set
*/
@JsonProperty
public void setFirstNameSet(boolean isFirstNameSet) {
this.isFirstNameSet = isFirstNameSet;
}
/**
* @return the isLastNameSet
*/
@JsonIgnore
@XmlTransient
public boolean isLastNameSet() {
return isLastNameSet;
}
/**
* @param isLastNameSet
* the isLastNameSet to set
*/
@JsonProperty
public void setLastNameSet(boolean isLastNameSet) {
this.isLastNameSet = isLastNameSet;
}
/**
* @return the isEmailSet
*/
@JsonIgnore
public boolean isEmailSet() {
return isEmailSet;
}
/**
* @param isEmailSet
* the isEmailSet to set
*/
@JsonProperty
public void setEmailSet(boolean isEmailSet) {
this.isEmailSet = isEmailSet;
}
/**
* @return the isAddressSet
*/
@JsonIgnore
public boolean isAddressSet() {
return isAddressSet;
}
/**
* @param isAddressSet
* the isAddressSet to set
*/
@JsonProperty
public void setAddressSet(boolean isAddressSet) {
this.isAddressSet = isAddressSet;
}
/**
* @return the isPhoneNumberSet
*/
@JsonIgnore
public boolean isPhoneNumberSet() {
return isPhoneNumberSet;
}
/**
* @param isPhoneNumberSet
* the isPhoneNumberSet to set
*/
@JsonProperty
public void setPhoneNumberSet(boolean isPhoneNumberSet) {
this.isPhoneNumberSet = isPhoneNumberSet;
}
/**
* @return the isPasswordSet
*/
@JsonIgnore
public boolean isPasswordSet() {
return isPasswordSet;
}
/**
* @param isPasswordSet
* the isPasswordSet to set
*/
@JsonProperty
public void setPasswordSet(boolean isPasswordSet) {
this.isPasswordSet = isPasswordSet;
}
/**
* @return the isUserRoleSet
*/
@JsonIgnore
public boolean isUserRoleSet() {
return isUserRoleSet;
}
/**
* @param isUserRoleSet
* the isUserRoleSet to set
*/
@JsonProperty
public void setUserRoleSet(boolean isUserRoleSet) {
this.isUserRoleSet = isUserRoleSet;
}
/**
* @return the isUserGroupSet
*/
@JsonIgnore
public boolean isUserGroupSet() {
return isUserGroupSet;
}
/**
* @param isUserGroupSet
* the isUserGroupSet to set
*/
@JsonProperty
public void setUserGroupSet(boolean isUserGroupSet) {
this.isUserGroupSet = isUserGroupSet;
}
/**
* @return the systemUser
*/
public boolean isSystemUser() {
return systemUser;
}
/**
* @param systemUser the systemUser to set
*/
public void setSystemUser(boolean systemUser) {
this.systemUser = systemUser;
}
/**
* @return the restrictedUser
*/
public boolean isRestrictedUser() {
return restrictedUser;
}
/**
* @param restrictedUser the restrictedUser to set
*/
public void setRestrictedUser(boolean restrictedUser) {
this.restrictedUser = restrictedUser;
}
@Override
public String toString() {
StringBuilder strb = new StringBuilder();
strb.append(" User Name = " + this.getUsername());
strb.append(" First Name = " + this.getFirstName());
strb.append(" Last Name = " + this.getLastName());
strb.append(" Email = " + this.getEmail());
strb.append(" Address = " + this.getAddress());
strb.append(" Phone number = " + this.getPhoneNumber());
strb.append(" User role = " + this.getRole());
strb.append(" User group = " + this.getUsergroup());
return strb.toString();
}
@Override
public boolean equals(Object o) {
if(o instanceof MacUser) {
MacUser user = (MacUser)o;
if(user.username.equals(username) &&
user.usergroup.equals(usergroup) &&
user.lastName.equals(lastName) &&
user.firstName.equals(firstName) &&
user.email.equals(email)) {
return true;
}
}
return false;
}
}
Thanks Arun
Fixed at 1.3.4-SNAPSHOT Now we have following annotations supported: @Api @ApiOperation @ApiParam @ApiResponse @ApiResponses
The rest of the swagger annotations do not seem to have clear mapping on RAML
Thanks for the quick turn around on this fix. PFB the observation on the fix # 52
Regards Arun
In the sample i have provided (above) , all the resources are having @Produce having XML as media type.
eg :
@GET
@Path("/{name}")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@AllowAccess(roles = {APIRole.END_USER, APIRole.GROUPADMIN})
@ApiResponses(value = { @ApiResponse(code=200, message="success", response=MacUser.class),
@ApiResponse(code=404, message="invalid user name")})
In RAML response 200 is generating the example section successfully but the schema section is only showing the reference name but there is no schema defined with that name under -Schemas seciton in RAML. It has only generated the schema refernce and definition for JSON type.
Regards Arun
Thanks for your info, digging into it. now.
Regards, Pavel
Hi, @arubalac
@XmlTransient is fixed Changes are deployed to 1.3.4-SNAPSOT
As for the XML schema, we do see it being generated. Does it still fail for you? If yes, please, provide more details as we can not reproduce the issue.
Regards, Konstantin
Hi @petrochenko-pavel-a and @KonstantinSviridov
Thanks for the update . I have tried testing the updated code (1.3.4-SNAPSHOT) . Following are the observations:
I was using the eclipse plugin>/b> for generating the RAML . @vebhhav will provide the apiraml.zip file.
Regards Arun
Any updates Pavel?
Sent from my iPhone
On Mar 30, 2015, at 7:42 AM, petrochenko-pavel-a notifications@github.com wrote:
Thanks for your info, digging into it. now.
Regards, Pavel
— Reply to this email directly or view it on GitHub.
Hi @vebhhav ,
Yet to get an update .
This is looking really good. One problem I've noticed (in 1.3.3 as well), is that the @Api(description="foo")
annotation on a resource generates the following in the RAML output
documentation:
- title: description
content: !include docs/description.md
But docs/description.md is nowhere to be found. (I'd actually prefer to see it just generate a text description based on the javadoc, but I can't seem to get that to work either). How do I get descriptions?
Hi guys, sorry I am extremely busy on other project right now, I promise to look/fix everything over weekend.
Regards, Pavel
On Thu, Apr 9, 2015 at 8:06 PM, Mike Griffith notifications@github.com wrote:
This is looking really good. One problem I've noticed (in 1.3.3 as well), is that the @Api(description="foo") annotation on a resource generates the following in the RAML output
documentation:
- title: description content: !include docs/description.md
But docs/description.md is nowhere to be found. (I'd actually prefer to see it just generate a text description based on the javadoc, but I can't seem to get that to work either). How do I get descriptions?
— Reply to this email directly or view it on GitHub https://github.com/mulesoft/raml-for-jax-rs/issues/52#issuecomment-91242733 .
Thanks Pavel..appreciate your effort in taking this to the end.
Regards -veb
Sent from my iPhone
On Apr 9, 2015, at 7:58 AM, petrochenko-pavel-a notifications@github.com wrote:
Hi guys, sorry I am extremely busy on other project right now, I promise to look/fix everything over weekend.
Regards, Pavel
On Thu, Apr 9, 2015 at 8:06 PM, Mike Griffith notifications@github.com wrote:
This is looking really good. One problem I've noticed (in 1.3.3 as well), is that the @Api(description="foo") annotation on a resource generates the following in the RAML output
documentation:
- title: description content: !include docs/description.md
But docs/description.md is nowhere to be found. (I'd actually prefer to see it just generate a text description based on the javadoc, but I can't seem to get that to work either). How do I get descriptions?
— Reply to this email directly or view it on GitHub https://github.com/mulesoft/raml-for-jax-rs/issues/52#issuecomment-91242733 .
— Reply to this email directly or view it on GitHub.
Thanks Pavel . Appreciate your effort.
There are a number of examples here:
https://github.com/swagger-api/swagger-core/tree/develop_2.0/samples
Swagger Annotations I'd like to see supported are @Api
@ApiOperation
@ApiParam
@ApiResponses
@ApiResponse
@ApiModel
and @ApiModelProperty
If the JAX-RS method took a Java POJO as parameter or returned it as response and it @Produces
@Consumes
"application/json"
it would be great if the generated RAML had a schema
and example
autogenerated from this json POJO
Hm actually it already should work for a plain case when method just returns a POJO. (but I think you need something a bit different).
Actually we support @Api @ApiOperation @ApiParam @ApiResponses @ApiResponse already but it is not totally clear for me how you see support for @ApiModel and @ApiModelProperty so it will be great if you will be able to describe how you see it in a bit more details (especially @ApiModelProperty)
Thanks in advance, Pavel
@bikegriffith, descriptions are fixed
Thanks a lot @petrochenko-pavel-a and @KonstantinSviridov, XML schema is getting generated as expected inline in RAML . XML pro-log issue also got resolved.
@vebhhav thanks for you support and coordination.
I am closing this issue for now, please let me know if something else needs to be improved.
Regards, Pavel
Hi Pavel,
We ran into one more ask from the Engineering Team. Their current code uses Custom Annotation @Relationships(values={"usergroup:/usergroups/{usergroup}"}) to provide additional links in REST response. Need suggestions for handling Custom Annotation support by the team as an extension to the RAML-for-JAX-RS utility. Kindly suggest how to go about this request.
Thanks and Regards, Venkatesh
-Swagger Annotations other than @APIResponse and @APIResponses are not supported; Example - @APIOperation;