Webflux doesn't support ResponseBodyAdvice yet? - spring

Since ResponseBodyAdvice interface is in web.servlet package
How could I implement such functions in webflux?

I also have this problem, i found it can be done by HandlerResultHandler.
For Example, I extend ResponseBodyResultHandler to wrap all my response
First, you should write ResponseWrapper.java
public class ResponseWrapper extends ResponseBodyResultHandler {
private static MethodParameter param;
static {
try {
//get new params
param = new MethodParameter(ResponseWrapper.class
.getDeclaredMethod("methodForParams"), -1);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public ResponseWrapper(List<HttpMessageWriter<?>> writers, RequestedContentTypeResolver resolver) {
super(writers, resolver);
}
private static Mono<Response> methodForParams() {
return null;
}
#Override
public boolean supports(HandlerResult result) {
boolean isMono = result.getReturnType().resolve() == Mono.class;
boolean isAlreadyResponse = result.getReturnType().resolveGeneric(0) == Response.class;
return isMono && !isAlreadyResponse;
}
#Override
#SuppressWarnings("unchecked")
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
Preconditions.checkNotNull(result.getReturnValue(), "response is null!");
// modify the result as you want
Mono<Response> body = ((Mono<Object>) result.getReturnValue()).map(Response::success)
.defaultIfEmpty(Response.success());
return writeBody(body, param, exchange);
}
}
Then, add Bean in SpringBootApplication
#SpringBootApplication
public class SmartApplication {
#Autowired
ServerCodecConfigurer serverCodecConfigurer;
#Autowired
RequestedContentTypeResolver requestedContentTypeResolver;
#Bean
ResponseWrapper responseWrapper() {
return new ResponseWrapper(serverCodecConfigurer
.getWriters(), requestedContentTypeResolver);
}
//Spring start
public static void main(String[] args) {
SpringApplication.run(SmartApplication.class, args);
}
}
My response class, for reference
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Response<T> {
boolean success;
T data;
Object error;
String warning;
public Response() {
}
public static Response success() {
return success(null);
}
public static <T> Response success(T data) {
return new Response<T>().setSuccess(true).setData(data);
}
public static Response error(Throwable e) {
LogManager.getLogger(StackLocatorUtil.getCallerClass(2)).info(e);
return new Response().setSuccess(false).setError(e);
}
public static Response error(Object e) {
return new Response().setSuccess(false).setError(e);
}
public static Response error(String e) {
return new Response().setSuccess(false).setError(e);
}
/* get success */
public boolean isSuccess() {
return success;
}
/* set success */
public Response setSuccess(boolean success) {
this.success = success;
return this;
}
/* get data */
public Object getData() {
return data;
}
/* set data */
public Response setData(T data) {
this.data = data;
return this;
}
/* get error */
public Object getError() {
return error;
}
/* set error */
public Response setError(Object error) {
this.error = error;
return this;
}
}

i used ResponseBodyAdvise before spring 5.0. i think ResponseBodyResultHandler suport webflux since spring5.0.

Related

How to properly inject ViewResolver?

I'm trying to implement this solution but ViewResolver is not injected and it's null. I'm using Spring boot 2.x
get contents of processed JSP into spring controller without using HttpClient?
I already researched online and read documentation.
How do I properly inject the ViewResolver so the solution works?
#Service
public class SpringUtils {
private static final Logger LOG = Logger.getLogger(SpringUtils.class);
#Autowired private ViewResolver viewResolver;
#Autowired private LocaleResolver localeResolver;
public String renderView(HttpServletRequest request, ModelAndView mav) {
try {
View view = viewResolver.resolveViewName(mav.getViewName(), localeResolver.resolveLocale(request));
HttpServletResponse localResponse = new MyHttpServletResponseWrapper(new DummyResponse());
view.render(mav.getModel(), request, localResponse);
return localResponse.toString();
} catch (Exception e) {
return "";
}
}
public boolean doesViewExist(HttpServletRequest request, String viewName) {
try {
if (viewResolver.resolveViewName(viewName, localeResolver.resolveLocale(request)) != null) {
return true;
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
return false;
}
static class MyHttpServletResponseWrapper extends HttpServletResponseWrapper {
private StringWriter sw = new StringWriter();
public MyHttpServletResponseWrapper(HttpServletResponse response) {
super(response);
}
public PrintWriter getWriter() throws IOException {
return new PrintWriter(sw);
}
public ServletOutputStream getOutputStream() throws IOException {
throw new UnsupportedOperationException();
}
public String toString() {
return sw.toString();
}
}
}
Dummy Response
public class DummyResponse implements HttpServletResponse {
public DummyResponse() {
}
public void setAppCommitted(boolean appCommitted) {}
public boolean isAppCommitted() { return false; }
public int getContentCount() { return -1; }
public boolean getIncluded() { return false; }
public void setIncluded(boolean included) {}
public String getInfo() { return null; }
public ServletResponse getResponse() { return null; }
public OutputStream getStream() { return null; }
public void setStream(OutputStream stream) {}
public void setSuspended(boolean suspended) {}
public boolean isSuspended() { return false; }
public void setError() {}
public boolean isError() { return false; }
public ServletOutputStream createOutputStream() throws IOException {
return null;
}
public void finishResponse() throws IOException {}
public int getContentLength() { return -1; }
public String getContentType() { return null; }
public PrintWriter getReporter() { return null; }
public void recycle() {}
public void write(int b) throws IOException {}
public void write(byte b[]) throws IOException {}
public void write(byte b[], int off, int len) throws IOException {}
public void flushBuffer() throws IOException {}
public int getBufferSize() { return -1; }
public String getCharacterEncoding() { return null; }
public void setCharacterEncoding(String charEncoding) {}
public ServletOutputStream getOutputStream() throws IOException {
return null;
}
public Locale getLocale() { return null; }
public PrintWriter getWriter() throws IOException { return null; }
public boolean isCommitted() { return false; }
public void reset() {}
public void resetBuffer() {}
public void setBufferSize(int size) {}
public void setContentLength(int length) {}
public void setContentType(String type) {}
public void setLocale(Locale locale) {}
public Cookie[] getCookies() { return null; }
public String getHeader(String name) { return null; }
public Collection<String> getHeaders(String arg0) { return null; }
public Collection<String> getHeaderNames() { return null; };
public String[] getHeaderValues(String name) { return null; }
public String getMessage() { return null; }
public int getStatus() { return -1; }
public void reset(int status, String message) {}
public void addCookie(Cookie cookie) {}
public void addDateHeader(String name, long value) {}
public void addHeader(String name, String value) {}
public void addIntHeader(String name, int value) {}
public boolean containsHeader(String name) { return false; }
public String encodeRedirectURL(String url) { return null; }
public String encodeRedirectUrl(String url) { return null; }
public String encodeURL(String url) { return null; }
public String encodeUrl(String url) { return null; }
public void sendAcknowledgement() throws IOException {}
public void sendError(int status) throws IOException {}
public void sendError(int status, String message) throws IOException {}
public void sendRedirect(String location) throws IOException {}
public void setDateHeader(String name, long value) {}
public void setHeader(String name, String value) {}
public void setIntHeader(String name, int value) {}
public void setStatus(int status) {}
public void setStatus(int status, String message) {}
}

How i can pass new Object between Zuul filters, using spring context?

Currently, I have AuthFilter and here I received an UserState. I need to pass it to the next Filter. But how to do it right? Or exists other practices to resolve it?
public class AuthFilter extends ZuulFilter {
#Autowired
private AuthService authService;
#Autowired
private ApplicationContext appContext;
#Override
public String filterType() {
return PRE_TYPE;
}
#Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER - 2;
}
#Override
public boolean shouldFilter() {
RequestContext context = RequestContext.getCurrentContext();
String requestURI = context.getRequest().getRequestURI();
for (String authPath : authPaths) {
if (requestURI.contains(authPath)) return true;
}
return false;
}
#Override
public Object run() throws ZuulException {
try {
UserState userState = authService.getUserData();
DefaultListableBeanFactory context = new DefaultListableBeanFactory();
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(UserState.class);
beanDefinition.setPropertyValues(new MutablePropertyValues() {
{
add("user", userState);
}
});
context.registerBeanDefinition("userState", beanDefinition);
} catch (UndeclaredThrowableException e) {
if (e.getUndeclaredThrowable().getClass() == UnauthorizedException.class) {
throw new UnauthorizedException(e.getMessage());
}
if (e.getUndeclaredThrowable().getClass() == ForbiddenException.class) {
throw new ForbiddenException(e.getMessage(), "The user is not allowed to make this request");
}
}
return null;
}
}
I pretty sure filters are chained together and the request/response are passed through them. You can add the data to the request, and have the next filter look for it.

Controller component issue with Spring and SockJs

I have a problem with a configuration of a WebSocket using Spring and SockJs.
I have configured all my app like Spring Documentation, the connection seems to be fine, but when I send a message the Controller is never involved and it doesn't work.
This is the Configuration component:
#Configuration
#EnableWebMvc
#EnableWebSocketMessageBroker
public class MyWebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer implements WebSocketConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/mySocket").withSockJS().setInterceptors(new MySocketHandshakeInterceptor());;
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app").enableSimpleBroker("/topic");
}
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
}
}
This is the HandshakeInterceptor implementation:
public class MySocketHandshakeInterceptor implements HandshakeInterceptor {
#Override
public void afterHandshake(ServerHttpRequest paramServerHttpRequest, ServerHttpResponse paramServerHttpResponse, WebSocketHandler paramWebSocketHandler, Exception paramException) {
// TODO Auto-generated method stub
System.out.println("MySocketHandshakeInterceptor afterHandshake");
}
#Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> paramMap)
throws Exception {
System.out.println("MySocketHandshakeInterceptor beforeHandshake");
return true;
}
}
This is the Controller component:
#Controller
public class MySocketController {
#MessageMapping("/testsocket")
#SendTo("/topic/testresponse")
public MessageOut test(MessageIn message) throws Exception {
System.out.println("MySocketController start");
System.out.println("MySocketController test "+ message);
return new MessageOut("test OK");
}
}
These are MessageIn and MessageOut:
public class MessageIn {
private String test;
/**
* #return the test
*/
public String getTest() {
return test;
}
}
public class MessageOut {
private String result;
public MessageOut(String result) {
super();
this.result = result;
}
/**
* #return the test
*/
public String getResult() {
return result;
}
/**
* #param result the result to set
*/
public void setResult(String result) {
this.result = result;
}
}
Finally, this is the client side (javascript):
var socketSession = {};
connectToMySocket();
function connectToVideoSocket() {
socketSession.socket = new SockJS("/mySocket");
socketSession.socket.stomp = Stomp.over(socketSession.socket);
socketSession.socket.stomp.debug = null;
socketSession.socket.stomp.connect({}, function () {
socketSession.socket.stomp.subscribe("/topic/testresponse", function (data) {
console.log(data);
});
});
}
This is the command that I launch to test the socket:
socketSession.socket.stomp.send("app/testsocket", {}, JSON.stringify({'test': 'test'}));
In the system out console I can only see the two rows:
MySocketHandshakeInterceptor beforeHandshake
MySocketHandshakeInterceptor afterHandshake
The interceptor works fine, but I don't see any print by the Controller component.
What's wrong?
Thanks.
I resolved by myself.
It was a problem of the client-side.
The correct script is:
var mySocket = undefined;
var stompClient = undefined;
connectToVideoSocket();
function connectToVideoSocket() {
mySocket = new SockJS('/mySocket');
stompClient = Stomp.over(mySocket);
stompClient.debug = null;
stompClient.connect({}, function(frame) {
stompClient.subscribe('/topic/testresponse', function(data){
console.log(JSON.parse(data.body).result);
});
});
}
In this way it works fine.

Problems with #Autowired, with a ManagedBean and an abstract class

Well, I have an abstract class like this:
public abstract class BasicCrudMBImpl<Bean, BO> extends BasicMBImpl {
protected Bean bean;
protected List<Bean> beans;
protected BO boPadrao;
public void deletar() {
try {
((BasicBO) boPadrao).delete((AbstractBean) bean);
addInfoMessage("Registro deletado com sucesso");
beans = retornaBeansDoBanco();
bean = null;
} catch (BOException e) {
addErrorMessage(e.getMessage());
}
}
public void salvar(ActionEvent event) {
try {
if (((AbstractBean) bean).getId() == null) {
bean = (Bean) ((BasicBO) boPadrao).save((AbstractBean) bean);
addInfoMessage("Registro salvo com sucesso");
} else {
((BasicBO) boPadrao).update((AbstractBean) bean);
addInfoMessage("Registro atualizado com sucesso");
}
beans = retornaBeansDoBanco();
} catch (BOException e) {
FacesContext.getCurrentInstance().validationFailed();
addErrorMessage(e.getMessage());
}
}
public Bean getBean() {
return bean;
}
public void setBean(Bean bean) {
this.bean = bean;
}
public List<Bean> getBeans() {
try {
if (beans == null)
beans = (List<Bean>) retornaBeansDoBanco();
return beans;
} catch (BOException e) {
addErrorMessage(e.getMessage());
}
return null;
}
public void setBeans(List<Bean> beans) {
this.beans = beans;
}
// Deve ser implementado para carregar a query adequada ao bean necessário
public abstract List<Bean> retornaBeansDoBanco();
public abstract void novo(ActionEvent event);
public abstract void alterar(ActionEvent event);
public BO getBoPadrao() {
return boPadrao;
}
public abstract void setBoPadrao(BO boPadrao);
public void addErrorMessage(String componentId, String errorMessage) {
addMessage(componentId, errorMessage, FacesMessage.SEVERITY_ERROR);
}
public void addErrorMessage(String errorMessage) {
addErrorMessage(null, errorMessage);
}
public void addInfoMessage(String componentId, String infoMessage) {
addMessage(componentId, infoMessage, FacesMessage.SEVERITY_INFO);
}
public void addInfoMessage(String infoMessage) {
addInfoMessage(null, infoMessage);
}
private void addMessage(String componentId, String errorMessage,
FacesMessage.Severity severity) {
FacesMessage message = new FacesMessage(errorMessage);
message.setSeverity(severity);
FacesContext.getCurrentInstance().addMessage(componentId, message);
}
}
In ManagedBean I tried to inject the "boPadrao" with #Autowired, like this:
#ManagedBean(name = "enderecoMB")
#ViewScoped
public class EnderecoMBImpl extends BasicCrudMBImpl<Endereco, BasicBO> {
private static Logger logger = Logger.getLogger(EnderecoMBImpl.class);
private List<TipoEndereco> tiposEndereco;
private List<Logradouro> logradouros;
#PostConstruct
public void init() {
logger.debug("Inicializando componentes no PostConstruct");
beans = retornaBeansDoBanco();
tiposEndereco = (List<TipoEndereco>) boPadrao
.findByNamedQuery(TipoEndereco.FIND_ALL);
logradouros = (List<Logradouro>) boPadrao
.findByNamedQuery(Logradouro.FIND_ALL_COMPLETO);
}
#Override
public List<Endereco> retornaBeansDoBanco() {
return (List<Endereco>) getBoPadrao().findByNamedQuery(Endereco.FIND_ALL_COMPLETO);
}
#Override
public void novo(ActionEvent event) {
bean = new Endereco();
}
#Override
public void alterar(ActionEvent event) {
// TODO Auto-generated method stub
}
public List<TipoEndereco> getTiposEndereco() {
return tiposEndereco;
}
public void setTiposEndereco(List<TipoEndereco> tiposEndereco) {
this.tiposEndereco = tiposEndereco;
}
public List<Logradouro> getLogradouros() {
return logradouros;
}
public void setLogradouros(List<Logradouro> logradouros) {
this.logradouros = logradouros;
}
#Autowired
public void setBoPadrao(BasicBO boPadrao) {
this.boPadrao = boPadrao;
}
}
But this doesn't works, the boPadrao is always null, getting a "NullPointerException". The error occurs in method retornaBeansDoBanco();

window scope in spring?

i was wondering about the spring scope equivalent to window scope ?
according to the documentation here
http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch04s04.html
i couldn't find any, so if there's a custom scope equivalent, can anyone please tell me, thanks.
EDIT: example of window scope in JSF
http://icefaces-showcase.icesoft.org/showcase.jsf?grp=compatMenu&exp=popup
One possible approach is having a session scoped bean that holds all the window sessions, and a window custom scope that access to the corresponding bean through that session scoped bean.
The required classes are:
Window Session
public class WindowSession {
private Map<String, Map<String,Object>> scopeMap = new HashMap<String, Map<String,Object>>();
private Map<String, Boolean> validSessions = new HashMap<String, Boolean>();
public WindowSession() {
super();
}
public Map<String, Map<String, Object>> getScopeMap() {
return scopeMap;
}
public void setScopeMap(Map<String, Map<String, Object>> scopeMap) {
this.scopeMap = scopeMap;
}
public Map<String, Boolean> getValidSessions() {
return validSessions;
}
public void setValidSessions(Map<String, Boolean> validSessions) {
this.validSessions = validSessions;
}
}
WindowIdContext
#Service
#Scope(value="request", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class WindowIdContext {
public static final String DEFAULT_SESSION_ID = "";
private String id = DEFAULT_SESSION_ID;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getQueryParamWithSessionId() {
if (DEFAULT_SESSION_ID.equals(id)) {
return "";
}
return "?" + WindowScope.WINDOW_ID_PARAM + "=" + id;
}
}
WindowSessionContext
#Service
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class WindowSessionContext {
private static SecureRandom random = new SecureRandom();
private WindowSession windowSession = new WindowSession();
#Autowired
private WindowIdContext windowIdContext;
public WindowSessionContext() {
windowSession.getValidSessions().put(WindowIdContext.DEFAULT_SESSION_ID, false);
}
public Object getObject(String name, ObjectFactory<?> objectFactory) {
String sessionId = windowIdContext.getId();
synchronized(this) {
if (!windowSession.getValidSessions().containsKey(sessionId)) {
windowSession.getValidSessions().put(sessionId, false);
}
Map<String,Object> sessionMap = windowSession.getScopeMap().get(sessionId);
if (sessionMap == null) {
sessionMap = new HashMap<String,Object>();
windowSession.getScopeMap().put(sessionId, sessionMap);
}
Object object = sessionMap.get(name);
if (object == null) {
object = objectFactory.getObject();
sessionMap.put(name, object);
}
return object;
}
}
public Object removeObject(String name) {
String sessionId = windowIdContext.getId();
synchronized(this) {
Map<String,Object> sessionMap = windowSession.getScopeMap().get(sessionId);
if (sessionMap == null) {
return null;
}
Object object = sessionMap.remove(name);
return object;
}
}
public String addSession() {
synchronized(this) {
String sessionId;
do {
sessionId = new BigInteger(130, random).toString(32);
} while (windowSession.getValidSessions().containsKey(sessionId));
windowSession.getValidSessions().put(sessionId, false);
return sessionId;
}
}
public void removeSession() {
String sessionId = windowIdContext.getId();
synchronized(this) {
windowSession.getScopeMap().remove(sessionId);
windowSession.getValidSessions().remove(sessionId);
}
}
public boolean isSessionValid(String sessionId) {
Boolean inUse = windowSession.getValidSessions().get(sessionId);
return inUse != null;
}
public boolean isSessionInUse(String sessionId) {
Boolean inUse = windowSession.getValidSessions().get(sessionId);
return inUse == true;
}
public synchronized boolean invalidateSession(String sessionId) {
Boolean valid = windowSession.getValidSessions().get(sessionId);
if (valid == null) {
return false;
}
if (sessionId.equals(WindowIdContext.DEFAULT_SESSION_ID)) {
windowSession.getValidSessions().put(sessionId, false);
} else {
windowSession.getValidSessions().remove(sessionId);
}
windowSession.getScopeMap().remove(sessionId);
for (Entry<String,Boolean> validSession : windowSession.getValidSessions().entrySet()) {
if (validSession.getValue() == true) {
return false;
}
}
return true;
}
public synchronized void setSessionInUse(String sessionId) {
windowSession.getValidSessions().put(sessionId, true);
}
public int getCount() {
return windowSession.getValidSessions().size();
}
}
WindowScope
public class WindowScope implements Scope {
private final int scope;
private static final int WINDOW_SCOPE = 40;
public static final String NAME = "window";
public static final String WINDOW_ID_PARAM = "windowid";
private ServletContext servletContext = null;
public WindowScope(ServletContext sc) {
servletContext = sc;
this.scope = WINDOW_SCOPE;
}
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
WindowSessionContext windowSessionContext = applicationContext.getBean(WindowSessionContext.class);
return windowSessionContext.getObject(name, objectFactory);
}
#Override
public Object remove(String name) {
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
WindowSessionContext windowSessionContext = applicationContext.getBean(WindowSessionContext.class);
return windowSessionContext.removeObject(name);
}
#Override
public String getConversationId() {
return RequestContextHolder.currentRequestAttributes().getSessionId();
}
#Override
public void registerDestructionCallback(String arg0, Runnable arg1) {
}
#Override
public Object resolveContextualObject(String key) {
return null;
}
protected int getScope() {
return this.scope;
}
}
WindowScopeFilter
#Component("windowScopeFilter")
public class WindowScopeFilter implements Filter {
#Autowired
private WindowSessionContext windowSessionContext;
#Autowired
private WindowIdContext windowIdContext;
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest)request;
HttpServletResponse httpResponse = (HttpServletResponse)response;
String sessionId = httpRequest.getParameter(WindowScope.WINDOW_ID_PARAM);
if (sessionId != null) {
if (windowSessionContext.isSessionValid(sessionId)) {
windowIdContext.setId(sessionId);
} else {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
} else {
windowSessionContext.setSessionInUse(WindowIdContext.DEFAULT_SESSION_ID);
}
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {
}
}
WindowScopeListener
#Component
public class WindowScopeListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
WebApplicationContext applicationContext = (WebApplicationContext)event.getApplicationContext();
Scope windowScope = new WindowScope(applicationContext.getServletContext());
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
beanFactory.registerScope("window", windowScope);
}
}
Source with complete source code: http://notwithoutmycode.com/post/window/scope/in/spring

Resources