Can anyone explain me why if I have my class so defined
public abstract class GenericClient
{
private static final Logger LOG = LoggerFactory.getLogger(GenericClient.class);
#Inject
#ConfigProperty( name = "dirx-ws.url" )
private String url;
private final Client client;
private HttpHeaders httpHeaders;
public GenericClient()
{
this.client = ClientBuilder.newClient();
}
public void setHttpHeaders( final HttpHeaders httpHeaders )
{
this.httpHeaders = httpHeaders;
}
protected HttpHeaders getHttpHeaders()
{
return this.httpHeaders;
}
protected Client getClient()
{
return this.client;
}
protected MultivaluedMap<String, Object> getHeaders()
{
final MultivaluedMap<String, String> myHttpHeaders = this.httpHeaders.getRequestHeaders();
final MultivaluedMap<String, Object> result = new MultivaluedHashMap<String, Object>();
myHttpHeaders.forEach(( name, values ) -> {
result.putSingle(name, values.size() != 1 ? values : values.get(0));
});
printHeaderInfo();
return result;
}
protected UriBuilder createURIBuilder( final String... paths )
{
final UriBuilder uriBuilder = UriBuilder.fromUri(this.url);
for (final String path : paths)
{
uriBuilder.path(path);
}
return uriBuilder;
}
}
there is no error, while if I define it this way (the only changes are private UriBuilder createdURI; and and the updated method createURIBuilder)
public abstract class GenericClient
{
private static final Logger LOG = LoggerFactory.getLogger(GenericClient.class);
#Inject
#ConfigProperty( name = "dirx-ws.url" )
private String url;
private final Client client;
private HttpHeaders httpHeaders;
private UriBuilder createdURI;
public GenericClient()
{
this.client = ClientBuilder.newClient();
}
public void setHttpHeaders( final HttpHeaders httpHeaders )
{
this.httpHeaders = httpHeaders;
}
protected HttpHeaders getHttpHeaders()
{
return this.httpHeaders;
}
protected Client getClient()
{
return this.client;
}
protected MultivaluedMap<String, Object> getHeaders()
{
final MultivaluedMap<String, String> myHttpHeaders = this.httpHeaders.getRequestHeaders();
final MultivaluedMap<String, Object> result = new MultivaluedHashMap<String, Object>();
myHttpHeaders.forEach(( name, values ) -> {
result.putSingle(name, values.size() != 1 ? values : values.get(0));
});
printHeaderInfo();
return result;
}
protected final UriBuilder createURIBuilder( final String... paths )
{
if (this.createdURI == null)
{
this.createdURI = UriBuilder.fromUri(this.url);
for (final String path : paths)
{
this.createdURI.path(path);
}
}
return this.createdURI;
}
}
I get the error
WELD-001410: The injection point has non-proxyable dependencies:
[BackedAnnotatedField] #Inject private
ch.ethz.id.sws.iamws.webservices.endpoint.RequestInterceptor.userClient
[INFO] at
ch.ethz.id.sws.iamws.webservices.endpoint.RequestInterceptor.userClient(RequestInterceptor.java:0)
My RequestScoped UserClient class has (only) an empty public constructor and it extends GenericClient.
Problem solved. Removing final from createURIBuilder method did the job.
I would be glad if someone could explain me anyway the reason why setting the method as 'final' is a problem.
Related
#Configuration
public class CustomRemoteTokenService implements ResourceServerTokenServices {
private static final Logger logger = LoggerFactory.getLogger(CustomRemoteTokenService.class);
#Resource
Environment environment;
private RestOperations restTemplate;
private String checkTokenEndpointUrl;
private String clientId;
private String clientSecret;
private String tokenName = "token";
private AccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();
#Autowired
public CustomRemoteTokenService() {
restTemplate = new RestTemplate();
((RestTemplate) restTemplate).setErrorHandler(new DefaultResponseErrorHandler() {
#Override
// Ignore 400
public void handleError(ClientHttpResponse response) throws IOException {
if (response.getRawStatusCode() != 400
&& response.getRawStatusCode() != 403 /* && response.getRawStatusCode() != 401 */) {
super.handleError(response);
}
}
});
}
public void setRestTemplate(RestOperations restTemplate) {
this.restTemplate = restTemplate;
}
public void setCheckTokenEndpointUrl(String checkTokenEndpointUrl) {
this.checkTokenEndpointUrl = checkTokenEndpointUrl;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public void setAccessTokenConverter(AccessTokenConverter accessTokenConverter) {
this.tokenConverter = accessTokenConverter;
}
public void setTokenName(String tokenName) {
this.tokenName = tokenName;
}
#Override
public OAuth2Authentication loadAuthentication(String accessToken)
throws AuthenticationException, InvalidTokenException, GenericException {
/*
* This code needs to be more dynamic. Every time an API is added we have to add
* its entry in the if check for now. Should be changed later.
*/
HttpServletRequest request = Context.getCurrentInstance().getRequest();
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add(tokenName, accessToken);
formData.add("api", environment.getProperty("resource.api"));
/* formData.add("api", "5b64018880999103244f1fdd");*/
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", getAuthorizationHeader(clientId, clientSecret));
Map<String, Object> map = null;
try {
map = postForMap(checkTokenEndpointUrl, formData, headers);
} catch (ResourceAccessException e) {
logger.error("Socket Exception occured at " + System.currentTimeMillis() + "for client_id : " + clientId);
GenericException ge = new GenericException(
"Could not validate your access token. If this occurs too often please contact MapmyIndia support at apisupport#mapmyindia.com");
ge.setHttpErrorCode(504);
ge.setOauthError("Access Token validation failed");
throw ge;
}
if (map.containsKey("error")) {
logger.error("check_token returned error: " + map.get("error") + " for client id : " + clientId);
String temp = map.get("error").toString();
GenericException ge = new GenericException(map.get("error_description").toString());
ge.setHttpErrorCode(Integer.parseInt(map.get("responsecode").toString()));
ge.setOauthError(temp);
switch (temp) {
case "invalid_token":
throw new InvalidTokenException(accessToken);
default:
throw ge;
}
}
Assert.state(map.containsKey("client_id"), "Client id must be present in response from auth server");
return tokenConverter.extractAuthentication(map);
}
#Override
public OAuth2AccessToken readAccessToken(String accessToken) {
throw new UnsupportedOperationException("Not supported: read access token");
}
private String getAuthorizationHeader(String clientId, String clientSecret) {
String creds = String.format("%s:%s", clientId, clientSecret);
try {
return "Basic " + new String(Base64.encode(creds.getBytes("UTF-8")));
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("Could not convert String");
}
}
private Map<String, Object> postForMap(String path, MultiValueMap<String, String> formData, HttpHeaders headers)
throws RestClientException {
if (headers.getContentType() == null) {
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
}
#SuppressWarnings("rawtypes")
Map map = restTemplate.exchange(path, HttpMethod.POST,
new HttpEntity<MultiValueMap<String, String>>(formData, headers), Map.class).getBody();
#SuppressWarnings("unchecked")
Map<String, Object> result = map;
return result;
}
}
I autowired Environment and getting null when I do environment.getProperty("resource.api");
It is always returning null but in another classes I autowire Environment and successfully retrieve the value from properties.
You have to take this steps :
1.Register a Properties
You need to register you properties file by #PropertySource("classpath:foo.properties") as :
#Configuration
#PropertySource("classpath:foo.properties")
public class CustomRemoteTokenService implements ResourceServerTokenServices {
//...
}
2.Injecting Properties
To obtain the value of a property with the Environment API:
#Autowired
private Environment env;
Is there a way to sort repository query results by querydsl alias?
So far I've managed to filter, but sorting results with an error:
org.springframework.data.mapping.PropertyReferenceException: No property username found for type User!
request:
GET /users?size=1&sort=username,desc
my rest controller method:
#GetMapping("/users")
public ListResult<User> getUsersInGroup(
#ApiIgnore #QuerydslPredicate(root = User.class) Predicate predicate,
Pageable pageable) {
Page<User> usersInGroup =
userRepository.findByGroup(CurrentUser.getGroup(), predicate, pageable);
return new ListResult<>(usersInGroup);
}
my repository:
#Override
default void customize(QuerydslBindings bindings, QUser root) {
bindings.including(root.account.login, root.account.firstName, root.account.lastName,
root.account.phoneNumber, root.account.email, root.account.postalCode, root.account.city,
root.account.address, root.account.language, root.account.presentationAlias);
bindAlias(bindings, root.account.login, "username");
}
default Page<User> findByGroup(Group group, Predicate predicate, Pageable pageable) {
BooleanExpression byGroup = QUser.user.group.eq(group);
BooleanExpression finalPredicate = byGroup.and(predicate);
return findAll(finalPredicate, pageable);
}
default void bindAlias(QuerydslBindings bindings, StringPath path, String alias) {
bindings.bind(path).as(alias).first(StringExpression::likeIgnoreCase);
}
I've also tried to implement my own PageableArgumentResolver based on QuerydslPredicateArgumentResolver, but some of the methods used there are package private so I thought maybe I am going in the wrong direction
I succeeded by creating a PageableArgumentResolver annotated with class type of query root class and adding alias registry to my generic repository interface.
This solution seems like a workaround but at least it works ;)
repository:
public interface UserRepository extends PageableAndFilterableGenericRepository<User, QUser> {
QDSLAliasRegistry aliasRegistry = QDSLAliasRegistry.instance();
#Override
default void customize(QuerydslBindings bindings, QUser root) {
bindAlias(bindings, root.account.login, "username");
}
default void bindAlias(QuerydslBindings bindings, StringPath path, String alias) {
bindings.bind(path).as(alias).first(StringExpression::likeIgnoreCase);
aliasRegistry.register(alias, path);
}
alias registry:
public class QDSLAliasRegistry {
private static QDSLAliasRegistry inst;
public static QDSLAliasRegistry instance() {
inst = inst == null ? new QDSLAliasRegistry() : inst;
return inst;
}
private QDSLAliasRegistry() {
registry = HashBiMap.create();
}
HashBiMap<String, Path<?>> registry;
resolver:
public class QDSLSafePageResolver implements PageableArgumentResolver {
private static final String DEFAULT_PAGE = "0";
private static final String DEFAULT_PAGE_SIZE = "20";
private static final String PAGE_PARAM = "page";
private static final String SIZE_PARAM = "size";
private static final String SORT_PARAM = "sort";
private final QDSLAliasRegistry aliasRegistry;
public QDSLSafePageResolver(QDSLAliasRegistry aliasRegistry) {
this.aliasRegistry = aliasRegistry;
}
#Override
public boolean supportsParameter(MethodParameter parameter) {
return Pageable.class.equals(parameter.getParameterType())
&& parameter.hasParameterAnnotation(QDSLPageable.class);
}
#Override
public Pageable resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {
MultiValueMap<String, String> parameterMap = getParameterMap(webRequest);
final Class<?> root = parameter.getParameterAnnotation(QDSLPageable.class).root();
final ClassTypeInformation<?> typeInformation = ClassTypeInformation.from(root);
String pageStr = Optional.ofNullable(parameterMap.getFirst(PAGE_PARAM)).orElse(DEFAULT_PAGE);
String sizeStr = Optional.ofNullable(parameterMap.getFirst(SIZE_PARAM)).orElse(DEFAULT_PAGE_SIZE);
int page = Integer.parseInt(pageStr);
int size = Integer.parseInt(sizeStr);
List<String> sortStrings = parameterMap.get(SORT_PARAM);
if(sortStrings != null) {
OrderSpecifier[] specifiers = new OrderSpecifier[sortStrings.size()];
for(int i = 0; i < sortStrings.size(); i++) {
String sort = sortStrings.get(i);
String[] orderArr = sort.split(",");
Order order = orderArr.length == 1 ? Order.ASC : Order.valueOf(orderArr[1].toUpperCase());
specifiers[i] = buildOrderSpecifier(orderArr[0], order, typeInformation);
}
return new QPageRequest(page, size, specifiers);
} else {
return new QPageRequest(page, size);
}
}
private MultiValueMap<String, String> getParameterMap(NativeWebRequest webRequest) {
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
for (Map.Entry<String, String[]> entry : webRequest.getParameterMap().entrySet()) {
parameters.put(entry.getKey(), Arrays.asList(entry.getValue()));
}
return parameters;
}
private OrderSpecifier<?> buildOrderSpecifier(String sort,
Order order,
ClassTypeInformation<?> typeInfo) {
Expression<?> sortPropertyExpression = new PathBuilderFactory().create(typeInfo.getType());
String dotPath = aliasRegistry.getDotPath(sort);
PropertyPath path = PropertyPath.from(dotPath, typeInfo);
sortPropertyExpression = Expressions.path(path.getType(), (Path<?>) sortPropertyExpression, path.toDotPath());
return new OrderSpecifier(order, sortPropertyExpression);
}
}
I'm writing tests for RESTful services in a legacy application using Resteasy Client and Embedded Jaxrs Server. I'm facing problems with Serialization/Deserialization using Jackson with a peculiar Entity, which I'm not supposed to do any changes. This Entity has:
A public "getter" that only performs logic (no equivalent field) and should be serializable, but not deserializable;
A private field used for certain controls and persistence, but without public getter/setter, shouldn't be Serialized/Deserialized;
While in the application our Front-end never sends those attributes back (so they're never deserialized), in my unit tests they are failing due to "org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field". If both properties above have their public getters/setters the test won't fail, but then again I'm not supposed to do changes to the code and those methods would break the architeture of those classes.
I've tweaked my Object Mapper but no configuration was able to deal with this scenario. Either one or another ends up being not found. Is there a way to turn of serialization in those cases by adjusting only my Object Mapper to ignore those properties? Or is it mandatory to have the code altered somehow?
Thanks!
(Small sample)
// Entity
public class Entidade {
private int numero;
private String dado;
private boolean naoUsado = false;
public Entidade() { /**/ }
public Entidade(int numero, String dado) {
this.numero = numero;
this.dado = dado;
}
public int getNumero() {
return numero;
}
public void setNumero(int numero) {
this.numero = numero;
}
public String getDado() {
return dado;
}
public void setDado(String dado) {
this.dado = dado;
}
public String getTeste() {
return "Regra de negócio de leitura";
}
}
// Embedded Server Helper
public class ServidorEmbarcadoRestEasy {
private static final int POOL_SIZE = 9999;
private static final int PORTA = 5555;
private static final String HOST = "localhost";
private TJWSEmbeddedJaxrsServer servidor;
private ResteasyClient resteasyClient;
private ServidorEmbarcadoRestEasy(Object webservice, Class<?>... providers) {
this.servidor = new TJWSEmbeddedJaxrsServer();
this.resteasyClient = new ResteasyClientBuilder().
connectionPoolSize(POOL_SIZE).
connectionCheckoutTimeout(100, TimeUnit.MILLISECONDS).
build();
servidor.setPort(PORTA);
servidor.setBindAddress(HOST);
servidor.getDeployment().getResources().add(webservice);
servidor.setSecurityDomain(null);
servidor.start();
ResteasyProviderFactory factory = servidor.getDeployment().getDispatcher().getProviderFactory();
for (Class<?> c : providers) {
factory.registerProvider(c);
}
}
public static ServidorEmbarcadoRestEasy iniciar(Object webservice, Class<?>... providers) {
ServidorEmbarcadoRestEasy servidorEmbarcado = new ServidorEmbarcadoRestEasy(webservice, providers);
return servidorEmbarcado;
}
public void fechar() {
servidor.stop();
}
private String getUrlCompleta(String uri) {
final String base = "http://%s:%s/%s";
return String.format(base, HOST, PORTA, uri);
}
private Builder request(String uri, List<String> queryParams) {
String urlCompleta = getUrlCompleta(uri);
ResteasyWebTarget target = resteasyClient.target(urlCompleta);
for (String s : queryParams) {
String[] chaveValor = s.split("=");
String chave = chaveValor[0];
String valor = chaveValor[1];
target = target.queryParam(chave, valor);
}
return target.request();
}
private Builder request(String uri) {
if (uri.contains("?")) {
String[] urlFracionada = uri.split("\\?");
String baseUri = urlFracionada[0];
String paramString = urlFracionada[1];
String[] paramArray = paramString.split("&");
List<String> parametros = new ArrayList<>(Arrays.asList(paramArray));
if (!parametros.isEmpty()) {
return request(baseUri, parametros);
}
}
String urlCompleta = getUrlCompleta(uri);
return resteasyClient.target(urlCompleta).request();
}
public Response get(String url) {
return request(url).buildGet().invoke();
}
public Response delete(String url) {
return request(url).buildDelete().invoke();
}
public Response put(String url, Object payload) {
return request(url).buildPut(Entity.json(payload)).invoke();
}
public Response post(String url, Object payload) {
return request(url).buildPost(Entity.json(payload)).invoke();
}
}
// Jackson Provider
public class JacksonTestsProvider extends JacksonJsonProvider {
public static ObjectMapper getMapper() {
return new ObjectMapper()
.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
#Override
public void writeTo(Object arg0, Class<?> arg1, Type arg2, Annotation[] arg3, MediaType arg4,
MultivaluedMap<String, Object> arg5, OutputStream arg6) throws IOException {
super.setMapper(getMapper());
super.writeTo(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
}
#Override
public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException {
super.setMapper(getMapper());
return super.readFrom(type, genericType, annotations, mediaType, httpHeaders, entityStream);
}
}
// Unit Tests
public class ServidorEmbarcadoRestEasyTest {
#Path("meuservico")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public static class ServicoTeste {
private Map<Integer, Entidade> entidades = new HashMap<>();
public ServicoTeste() {
for (int i = 1; i <= 100; i++) {
entidades.put(i, new Entidade(i, "Teste " + i));
}
}
#GET
#Path("minha-entidade")
public Response getEntidade() {
return Response.ok(new Entidade(9999, "Nova entidade")).build();
}
#GET
#Path("minha-entidade/{id}")
public Response getEntidade(#PathParam("id") Integer id) {
Entidade retorno = entidades.get(id);
if (retorno == null) {
return Response.status(Status.BAD_REQUEST).build();
} else {
return Response.ok(retorno).build();
}
}
}
private static ServidorEmbarcadoRestEasy servidor;
private static ServicoTeste servico;
#BeforeClass
public static void setUpBeforeClass() throws Exception {
servico = new ServicoTeste();
servidor = ServidorEmbarcadoRestEasy.iniciar(servico,
JacksonTestsProvider.class);
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
servidor.fechar();
}
#Test
public void deveFazerGetComSucesso() {
Response response = servidor.get("meuservico/minha-entidade");
assertEquals(Status.OK.getStatusCode(), response.getStatus());
Entidade entidade = response.readEntity(Entidade.class);
assertEquals(9999, entidade.getNumero());
assertEquals("Nova entidade", entidade.getDado());
response = servidor.get("meuservico/minha-entidade/98");
assertEquals(Status.OK.getStatusCode(), response.getStatus());
entidade = response.readEntity(Entidade.class);
assertEquals(98, entidade.getNumero());
assertEquals("Teste 98", entidade.getDado());
}
}
AdminSOAPRunner:
#Component
public class AdminSOAPRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(AdminSOAPRunner.class);
private String userId;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
#Autowired
private AdminAuth adminAuthenticator;
#Autowired
private AdminBean adminBean;
private AccountService accountService;
private void setBindingProviderByAccountService() {
WSBindingProvider bindingProvider = (WSBindingProvider) this.accountService;
bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, adminBean.getAccountUrl());
LOGGER.info("Endpoint {}", adminBean.getAccountUrl());
}
private RequestInfo getRequestInfo() {
RequestInfo requestInfo = new RequestInfo();
requestInfo.setAppName(adminBean.getAppName());
requestInfo.setUserId(this.getUserId());
requestInfo.setTrace(UUID.randomUUID().toString());
return requestInfo;
}
public List<ApplyAccountResult> getAccounts(ApplyAccountRequest request) {
AccountService_Service service = null;
URL serviceWSDL = AccountService_Service.class.getResource("/Account-service/Account-service.wsdl");
service = new AccountService_Service(serviceWSDL);
SOAPHandlerResolver SOAPHandlerResolver = new SOAPHandlerResolver();
SOAPHandlerResolver.getHandlerList().add(new SOAPHandler(this.adminAuthenticator));
service.setHandlerResolver(SOAPHandlerResolver);
if (accountService == null) {
accountService = service.getAccountService();
}
setBindingProviderByAccountService();
ApplyAccountAccountResponse response = null;
LOGGER.info("Making a SOAP request.");
response = AccountService.applyAccount(request, getRequestInfo(), new Holder<ResponseInfo>());
LOGGER.info("SOAP request completed.");
return response.getApplyAccountResults();
}
SOAPHandlerResolver:
public class SOAPHandlerResolver implements HandlerResolver {
#SuppressWarnings("rawtypes")
private List<Handler> handlerList;
public SOAPHandlerResolver() {
this.handlerList = null;
}
#SuppressWarnings("rawtypes")
public List<Handler> getHandlerList() {
if (this.handlerList == null) {
this.handlerList = new ArrayList<>();
}
return this.handlerList;
}
#SuppressWarnings("rawtypes")
#Override
public List<Handler> getHandlerChain(PortInfo portInfo) {
List<Handler> handlerChain = new ArrayList<>();
if (this.handlerList == null || this.handlerList.isEmpty()) {
this.handlerList = new ArrayList<>();
this.handlerList.add(new SOAPHandler(null));
}
handlerChain.addAll(this.handlerList);
return handlerChain;
}
}
SOAPHandler
public class SOAPHandler implements SOAPHandler<SOAPMessageContext> {
private AdminAuth adminAuth;
private static final Logger LOGGER = LoggerFactory.getLogger(SOAPHandler.class);
public MosaicOnboardSOAPHandler(AdminAuth adminAuth) {
if (adminAuth == null) {
adminAuth = new AdminAuth();
LOGGER.info("AdminAuth found null. Creating new adminAuth instance.");
}
this.adminAuth = adminAuth;
}
#Override
public boolean handleMessage(SOAPMessageContext context) {
Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty) {
#SuppressWarnings("unchecked")
Map<String, List<String>> headers = (Map<String, List<String>>) context.get(MessageContext.HTTP_REQUEST_HEADERS);
if (headers == null) {
headers = new HashMap<>();
context.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
}
List<String> cookie = headers.get("Cookie");
if (cookie == null) {
cookie = new ArrayList<>();
headers.put("Cookie", cookie);
}
cookie.add(this.adminAuth.getToken());
}
return true;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
return false;
}
#Override
public void close(MessageContext context) {
}
#Override
public Set<QName> getHeaders() {
return null;
}
}
AdminAuth:
#Component
public class AdminAuth {
#Autowired
private AdminBean adminBean;
private static final Logger LOG = LoggerFactory.getLogger(Admin.class);
private String token;
private void generateToken() {
try {
AdminTokenHelper adminTokenHelper = new AdminTokenHelper(adminBean.getAutheticationServerURL(), adminBean.getLicense());
token = adminTokenHelper.getToken(adminBean.getUsername(), adminBean.getPassword().toCharArray());
LOG.info("Token generation successful");
} catch (Exception ex) {
ex.printStackTrace();
LOG.error("Token generation failed");
LOG.error(ex.getMessage());
throw new RuntimeException("Token generation failed", ex);
}
}
#Cacheable(value = "tokenCache")
public String getToken() {
LOG.warn("Token not available. Generating a new token.");
generateToken();
return token;
}
}
ehcache.xml
<cache name="tokenCache" maxEntriesLocalHeap="1" eternal="false" timeToIdleSeconds="895" timeToLiveSeconds="895" memoryStoreEvictionPolicy="LRU"/>
Applcation
#EnableCaching
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.sources(Application.class).profiles(determineEnvironmentProfile());
}
}
In AdminAuth, it uses functional user to generate token. the token generated for authentication expires in 15 minutes. So my purpose was to write cache so that all the calls from ui can use the same token regardless of actual user. So i set the time 14:55 to generate new token. Now the problem comes when it's after 15 minutes and the cache doesn't evict the old toeken so that call uses the old and expired token and it fails.
I tried different eviction policies like LRU, LFU, FiFO but nothing is working. The calls are coming from ui through tomcat container in spring boot 1.3.
Why is this not getting evicted? What am i missing? Any help is appreciated
Replace #Cacheable(value = "tokenCache") with #Cacheable("tokenCache")
From the comments:
The dependency on spring-boot-starter-cache was missing. This prevented Spring Boot from automatically configuring the CacheManager. Once this dependency was added, the cache configuration worked.
See http://docs.spring.io/spring-boot/docs/1.3.x/reference/html/boot-features-caching.html
I have a decent amount of experience with REST and JSON, but I'm failing at coming up with a way to read some JSON as a Java object.
The response is here: https://api.kraken.com/0/public/OHLC?pair=XBTCZEUR&interval=60
Notice how one of the names (the relevant data) is dependent on a query parameter. I'm not sure how to create a Java object for Gson to use for deserialization, as one of the variable names can change.
I thought that maybe using a JsonReader to read the response in a streaming fashion might work, but when I do this I get a 403 error response.
Any ideas?
If you don't have exact knowledge regarding what the response will contain, you can always use an implementation of map class to pass on to gson, as I have tried to demonstrate in here :
public class RestResponse {
private boolean success;
private String errorDescription;
private Map<String, Object> data;
private static Gson GSON = new Gson();
private RestResponse()
{
data = new HashMap<String, Object>();
}
public boolean isSuccess() {
return success;
}
private void setSuccess(boolean success) {
this.success = success;
}
public String getErrorDescription() {
return errorDescription;
}
private void setErrorDescription(String errorDescription) {
this.errorDescription = errorDescription;
}
public Object getData(String... nestedKeys)
{
List<String> nestedKeysAsList = Arrays.asList(nestedKeys);
return getData(nestedKeysAsList);
}
public Object getData(List<String> nestedKeys)
{
String firstKey = nestedKeys.get(0);
if(!data.containsKey(firstKey))
throw new IllegalArgumentException("Key not found");
Object mapValue = data.get(firstKey);
if(!(mapValue instanceof Map))
return mapValue;
String finalKey = nestedKeys.get(nestedKeys.size()-1);
if(nestedKeys.size() > 2)
{
for(String nextKey : nestedKeys.subList(1,nestedKeys.size()-1))
{
Map<String,Object> tempMap = (Map)mapValue;
mapValue = tempMap.get(nextKey);
}
}
Map<String,Object> tempMap = (Map)mapValue;
return tempMap.get(finalKey);
}
private Map<String, Object> getData() {
return data;
}
private void setData(Map<String, Object> map){
this.data = map;
}
public static RestResponse createUnsuccessfulResponse(Exception e)
{
return createUnsuccessfulResponse(e.getMessage());
}
public static RestResponse createUnsuccessfulResponse(String reason)
{
RestResponse res = new RestResponse();
res.setSuccess(false);
res.setErrorDescription(reason);
return res;
}
public static RestResponse createSuccessfulResponse(String jsonString)
{
Map<String, Object> jsonToDataMap = GSON.fromJson(jsonString, Map.class);
return createSuccessfulResponseByMap(jsonToDataMap);
}
private static RestResponse createSuccessfulResponseByMap(Map<String, Object> jsonToDataMap)
{
RestResponse res = new RestResponse();
res.setSuccess(true);
res.setErrorDescription("Success");
res.setData(jsonToDataMap);
return res;
}
}
Usage examples can be found over here :
https://github.com/cgunduz/btcenter/blob/master/src/main/java/com/cemgunduz/utils/entity/RestResponse.java