when I'm trying to configure everything for swagger, it's working.. somehow partially, it ignores functions from resource and consider only #Api adnotation of the class
I'm using apache cxf + spring
Generated json contains only class description, no methods here
..."apis":[{"path":"/","description":"Entities operations"}]...
The controller adnotations
#Path("/")
#Api(value = "/", description = "Entities operations")
#Controller
public class RepositoryResource
....
The function adnotation
#GET
#ApiOperation(value = "Method to check if this resources is up and running")
public String hello()
...
Log message spoted
Could not find a definition for bean with id {http://listing.jaxrs.swagger.wordnik.com/}ApiListingResourceJSON.http-destination
spring configuration
<jaxrs:server id="restAPI" address="/" staticSubresourceResolution="true">
<jaxrs:serviceBeans>
<ref bean="swaggerResourceJSON"/>
<ref bean="repositoryResource"/>
</jaxrs:serviceBeans>
....
Don't use a root ("/") for your #Api value - that would break the documentation. Even if you have #Path("/"), you should have something like #Api("/root").
This does not affect the API itself, only where the documentation is served.
Once you make that modification, your /api-docs would look like:
..."apis":[{"path":"/root","description":"Entities operations"}]...
And that resource would be available on /api-docs/root. Running it with swagger-ui will produce the proper API calls.
Related
I am trying to instantiate a resolver from spring-cloud-aws-messaging, specifically the NotificationMessageArgumentResolver. The problem is that it takes a MessageConvertor as an argument. So, this is what I have so far:
private NotificationMessageArgumentResolver notificationMessageArgumentResolver() {
new NotificationMessageArgumentResolver(this.messageConvertor);
}
To get the messageConvertor, I have tried:
#Autowired
public MvcConfig(MessageConvertor messageConvertor) {}
#Autowired
public MvcConfig(MappingJackson2MessageConverter messageConvertor) {}
but I get the same error either ways no bean found. The documentation is simply asking to use the XML:
<mvc:annotation-driven>
<mvc:argument-resolvers>
<ref bean="notificationResolver" />
</mvc:argument-resolvers>
<aws-messaging:notification-argument-resolver id="notificationResolver" />
Which, according to the doc
registers three argument resolvers: NotificationStatusHandlerMethodArgumentResolver, NotificationMessageHandlerMethodArgumentResolver, and NotificationSubjectHandlerMethodArgumentResolver.
So, following the answer from How to use argument-resolvers using annotation in Spring boot?, I am able to get 2 of the 3 beans added, as they don't need any beans I cannot access, however I am not able to instantiate NotificationMessageArgumentResolver due to the lack of a MessageConvertor. I am expecting all my messages to come purely in JSON, so I do know exactly which MessageConvertor to use, which is the default one for JSON that ships with Spring Boot.
EDIT
The entire file, if anyone is interested: http://pastebin.com/tM471AEv
I wonder if you really need the NotificationMessageArgumentResolver as that is intended to be used when using messaging. As you can see it implements the HandlerMethodArgumentResolver from the org.springframework.messaging package.
I suspect that you want to use the NotificationMessageHandlerMethodArgumentResolver instead. Which is the HandlerMethodArgumentResolver for use with the web instead of messaging. Which is also registered when using <aws-messaging:notification-argument-resolver id="notificationResolver" />
I would also suggest to use the NotificationHandlerMethodArgumentResolverFactoryBean instead of 3 individual beans as that is also the class that is used internally by the namespace and annotation driven configuration.
Your configuration would look something like this.
#Bean
public NotificationHandlerMethodArgumentResolverFactoryBean notificationHandlerMethodArgumentResolverFactoryBean() {
return new NotificationHandlerMethodArgumentResolverFactoryBean();
}
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(notificationHandlerMethodArgumentResolverFactoryBean.getObject());
}
How do you parse spring (web) security expressions like hasRole('admin') programmatically (without using tags, annotations or ...)? (reference doc)
I've found Spring: What parser to use to parse security expressions - but I don't know how to find or build the EvaluationContext e.g. inside a spring controller.
Without providing an EvaluationContext gives
org.springframework.expression.spel.SpelEvaluationException: EL1011E:(pos 0): Method call: Attempted to call method hasRole(java.lang.String) on null context object
you need to add several things in order to get this thing working. You have to plug into the Spring's security API. Here's how I did it and it is working fine with Spring 3.2.
First as it was stated before you must have similar configuration in your spring-context.xml:
<security:http access-decision-manager-ref="customAccessDecisionManagerBean">
<security:http/>
<bean id="customWebSecurityExpressionHandler"
class="com.boyan.security.CustomWebSecurityExpressionHandler"/>
<bean id="customAccessDecisionManagerBean"
class="org.springframework.security.access.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter">
<property name="expressionHandler" ref="customWebSecurityExpressionHandler" />
</bean>
</list>
</property>
</bean>
This defines a new expressionHandler to override the default one for the WebExpressionVoter. Then we add this new decision voter to the decision manager. CustomWebSecurityExpressionHandler's purpose it to control the creation of SecurityExpressionRoot. So far so good. The question is why do you need a CustomWebSecurityExpressionRoot and the answer is simple as that - you define your custom security methods there. Having this in mind we can write the following classes:
public class CustomWebSecurityExpressionHandler extends DefaultWebSecurityExpressionHandler {
#Override
protected SecurityExpressionOperations createSecurityExpressionRoot(
Authentication authentication, FilterInvocation fi) {
CustomWebSecurityExpressionRoot expressionRoot =
new CustomWebSecurityExpressionRoot(authentication, delegationEvaluator);
return expressionRoot;
}
}
}
public class CustomWebSecurityExpressionRoot extends WebSecurityExpressionRoot {
public CustomWebSecurityExpressionRoot(Authentication auth, FilterInvocation fi) {
super(auth, fi);
}
// in here you must define all of the methods you are going to invoke in #PreAuthorize
// for example if you have an expression with #PreAuthorize('isBoyan(John)')
// then you must have the following method defined here:
public boolean isBoyan(String value) {
//your logic goes in here
return "Boyan".equalsIgnoreCase(value);
}
}
If you want to get a reference to the ExpressionParser you can use the following method AbstractSecurityExpressionHandler.getExpressionParser(). It is accessible through CustomWebSecurityExpressionHandler. Also you can take a look at its API if you want to do something more specific.
I hope this answers you question.
I am trying to follow the tutorial at:
http://pfelitti87.blogspot.be/2012/07/rest-services-with-spring-3-xml-json.html
Which basically is a tutorial on how to automatically convert your spring controller response to JSON\XML. The latter uses xstream.
And my configuration is exactly the same as his (besides the packages to scan obviously).
And my JSON url looks like I'd expect, however the .xml url does not return what I'd expect.
It starts with:
<?xml version="1.0"?>
<org.springframework.validation.BeanPropertyBindingResult><nestedPath/>
<nestedPathStack serialization="custom"><unserializable-parents/><vector>
<default><capacityIncrement>0</capacityIncrement><elementCount>0</elementCount>
<elementData><null/><null/><null/><null/><null/><null/><null/><null/><null/><null/></elementData></default></vector></nestedPathStack><objectName>coursesTakenForDealer</objectName>-<messageCodesResolver class="org.springframework.validation.DefaultMessageCodesResolver"><prefix/><formatter class="org.springframework.validation.DefaultMessageCodesResolver$Format">PREFIX_ERROR_CODE</formatter></messageCodesResolver>
And only contains the actual returned object towards the end.
Additionally it seems to ignore the #XmlAttribute and #XmlElement annotations.
I have a name instance variable on my Person class marked as #XmlAttribute yet it is converted as:
<person>
<name>Jack</name>
</person>
Any advice on how to resovle this\references to a better tutorial (perhaps using jaxb) would be much appreciated.
Edit:
As requested, part of my output (it does not completely fit in here). It is invoked using : http://localhost:8080/restTestApp/interestingPeople.xml
edit2:
The controller:
#Controller
public class InterestingPeopleController {
#RequestMapping(value="interestingPeople", method = GET)
public InterestingPeople getCoursesTakenByDealers() {
InterestingPeople interestingPeople;
//some logic (service calls etc) to fill it in
return interestingPeople;
}
}
edit 3:
I was able to resolve this by adding:
<property name="supportedClasses">
<list>
<value>com.jackdans.model.InterestingPeople</value>
</list>
</property>
to my XStreamMarshaller bean configuration.
I have a Rest service using Resteasy (running on top of Appengine), with the following psuedo code:
#Path("/service")
public class MyService {
#GET
#Path("/start")
public Response startService() {
// Need to read properties file here.
// like: servletContext.getResourceAsStream("/WEB-INF/config.properties")
}
}
However its obvious that the servlet context cannot be accessed here.
And code like:
InputStream inputStream = this.getClass().getClassLoader()
.getResourceAsStream("/WEB-INF/config.properties");
Can't be executed within the Appengine environment.
EDIT:
I have tried doing it with Spring like:
appContext.xml
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="/WEB-INF/auth.properties"/>
</bean>
Then, put this on the actual class fields:
#Path("/service")
public MyService{
#Autowired
#Value("${myservice.userid}")
private String username;
#Autowired
#Value("${myservice.passwd}")
private String password;
// Code omitted
}
However, part of the code of the MyService complains because the username and password was not "injected", I mean its empty although its on the auth.properties file
In RESTEasy you can easily inject Servlet context via #Context annotation: http://docs.jboss.org/resteasy/docs/2.3.1.GA/userguide/html_single/index.html#_Context
Examples can be found here: Rest easy and init params - how to access?
This should work if you put the file in /WEB-INF/classes/ (which, importantly, is on the classpath), specifying config.properties as a file at the top-level.
this.getClass().getClassLoader().getResourceAsStream("/config.properties");
See this similar question: How to load properties file in Google App Engine?
Edit: Now you've edited, I'll respond & answer the Spring-related question. So, put the auth.properties into /WEB-INF/classes/ , and then specify classpath as follows.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:auth.properties"/>
</bean>
I have a Spring mvc (3.1.1) app, and I want to define conditions beyond what's available in RequestMapping. I have a couple of things I want to use it for.
First, it would be nice if I could show a different home page for different user types:
#Controller
public class HomepageController {
#RequestMapping(value = "/")
#CustomCondition(roles = Guest.class)
public String guestHome() { /*...*/ }
#RequestMapping(value = "/")
#CustomCondition(roles = Admin.class)
public String adminHome() { /*...*/ }
}
Second, I want the app to function both as a web site and as a REST service (e.g. for mobile apps), so I'd want to let the website access both html and json actions, and let the service (different subdomain) only access json actions (some kind of #CustomCondition(web = true) which only matches website urls)
Can this work for any of the two uses I'm planning?
I found very little documentation about custom conditions, but I did find one example that implements custom conditions which might be what I want, but it uses a #Configuration class instead of the XML configuration which I'm using and I don't want to move my entire spring xml definitions to a #Configuration class.
Can I define a customMethodCondition for RequestMappingHandlerMapping in the XML?
I tried subclassing RequestMappingHandlerMapping and override getCustomMethodCondition, to return my custom RequestCondition, but it didn't work - getMatchingCondition() in my condition didn't fire.
Any help would be greatly appreciated!
UPDATE
I read a little more, and it looks like RequestMappingHandlerMapping is a new class (since ver 3.1).
What happens in my app is that the #Configuration that tries to override and thereby redefine the requestMappingHandlerMapping bean actually works, but the url mappings (#RequestMapping methods in #Controllers) seem to get processed twice, once by the subclass ExtendedRequestMappingHandlerMapping and once by the original RequestMappingHandlerMapping --first with a custom condition, and then again without it.
Bottom line is my custom conditions are simply ignored.
This is supposed to be an advanced pattern, but IMO it should be quite common...
Comments anyone?
Spring MVC already provides a mechanism for distinguishing between json and html, the RequestMapping annotation takes a consumes attribute which looks at the content type of the request...
// REST version, Content-type is "application/json"
#RequestMapping(value = "/", consumes = "application/json")
public void myRestService() {
...
// HTML version, Content-type is not "application/json"
#RequestMapping(value = "/", consumes = "!application/json")
public void myHtmlService() {
...
Another way to use the same url but have distinct methods is with the param or headers attribute...
// the url is /?role=guest
#RequestMapping(value = "/", param = "role=guest")
public void guestService() {
// the url is / with header role=admin
#RequestMapping(value = "/", headers = "role=admin")
public void adminService() {
I would think you would want distinct urls for security. Typically, with something like Spring Security, you would put all of the admin functionality under /admin and let the framework manage it all...
<http auto-config="true">
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
...
Would this be sufficient for your use case(s)?
If you have extended RequestMappingHandlerMapping(say ExtendedRequestMappingHandlerMapping) you have to register this new mapping a little differently in application context xml.
You cannot use <mvc:annotation-driven/> to configure the Spring MVC as that defines it's own handlerMapping internally, you can instead do something along these lines(or follow the approach in the link with #Configuration that you have provided):
<bean name="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService"></property>
<property name="validator">
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
</property>
</bean>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</list>
</property>
</bean>
<bean name="handlerMapping" class="..ExtendedRequestMappingHandlerMapping">
</bean>
This should ensure that your mapping takes effect and will ensure that the appropriate handler method is found by the handlerAdapter component.