I'm trying to use Kotlin for Google Java Cloud Endpoints, but I'm getting the following Exception deserializing Kotlin data classes
INFO: exception occurred while calling backend method
com.google.api.server.spi.response.BadRequestException: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of my.package.Foo: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: UNKNOWN; line: -1, column: -1]
at com.google.api.server.spi.request.RestServletRequestParamReader.read(RestServletRequestParamReader.java:128)
at com.google.api.server.spi.SystemService.invokeServiceMethod(SystemService.java:349)
at com.google.api.server.spi.handlers.EndpointsMethodHandler$RestHandler.handle(EndpointsMethodHandler.java:119)
at com.google.api.server.spi.handlers.EndpointsMethodHandler$RestHandler.handle(EndpointsMethodHandler.java:102)
at com.google.api.server.spi.dispatcher.PathDispatcher.dispatch(PathDispatcher.java:50)
at com.google.api.server.spi.EndpointsServlet.service(EndpointsServlet.java:71)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
...
My Kotlin files...
// file: Foo.kt
data class Foo(val bar: String) {
}
// file: MyEndpoint.kt
// My GET works fine as Serialization Does work
#ApiMethod(name = "getFoo",
description = "testing get",
path = "getFoo",
httpMethod = ApiMethod.HttpMethod.GET)
fun getFoo(): Foo {
val myFoo = Foo("myBar")
return myFoo
}
// My Post doesn't work, de-serialization is broken
#ApiMethod(name = "postFoo",
description = "testing post",
path = "postFoo",
httpMethod = ApiMethod.HttpMethod.POST)
fun postFoo(myFoo: Foo): Foo {
val postFoo = Foo(myFoo.bar)
return postFoo
}
I can see that I need to add the KotlinModule to the Jackson ObjectMapper
// file: build.gradle
compile("com.fasterxml.jackson.module:jackson-module-kotlin:2.8.4")
// adding this will fix the problem, but Where??
objectMapper.registerModule(new KotlinModule());
Where do I manupulate the 'Global' ObjectMapper for Java Endpoints?
I can see that I could add a Transformer to either the #Api or the data classes themselves.
If I add it to the #Api, I don't appear to get any type information, so that's out
Adding it to the data classes involves me making another Transformer for Every data class. Which
seems it would work, but adds A LOT of cruft.
Is there an elegant solution for setting/modifying the default ObjectMapper?
Related
1、Can I use bulkhead pattern in feignClient?
2、I have some confusion about hystrix.
For example,if I only have three feign clients "a","b","c"。The "a" calls "b" and "c".
I know I can easily use circuit breaker with fallback parameter and some Configuration like this:
#FeignClient(name = "b", fallback = bFallback.class)
protected interface HystrixClient {
//some methods
}
#FeignClient(name = "c", fallback = cFallback.class)
protected interface HystrixClient {
//some methods
}
In another way,I could use #HystrixCommand to wrap my remote call with some Configuration like this:
#HystrixCommand(fallbackMethod="getFallback")
public Object get(#PathVariable("id") long id) {
//...
}
In addition I can configure some parameter in #HystrixCommand or application.yml,and I also can add threadPoolKey in in #HystrixCommand
Q1:I have learn that Hystrix wrapped remote call to achieve purpose,I can understand on the latter way,but the former way likes wrapping callee?
I found in document that:
Feign will wrap all methods with a circuit break
Is this mean FeignClient seems adding #Hystrixcommand on every method in interface in essence?
Q2:If the Feign client "b" have three remote call,how can I let them run in bulkhead to avoid one method consuming all thread? to Combine the feignClient and #HystrixCommand? will them conflict?
Because I do not found the parameter likes threadPoolKey in feignClient. Auto bulkhead?
Q3:If my hystrix configuration is in application.yml ,the feignClient pattern and #HytirxCommand pattern whether have the same configuration pattern? like this:
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds:1000
circuitBreaker:
requestVolumeThreshold:10
...
...
but what's the follow Timeout?
feign:
client:
config:
feignName:
connectTimeout: 5000
readTimeout: 5000
1、Can I use bulkhead pattern in feignClient?
Java doc of setterFactory() method of HystrixFeign class says:
/**
* Allows you to override hystrix properties such as thread pools and command keys.
*/
public Builder setterFactory(SetterFactory setterFactory) {
this.setterFactory = setterFactory;
return this;
}
https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html says:
Spring Cloud Netflix does not provide the following beans by default for feign, but still looks up beans of these types from the application context to create the feign client:
• Logger.Level
• Retryer
• ErrorDecoder
• Request.Options
• Collection
• SetterFactory
So we should create setterFactory and specifying thread pool there. You can create a Bean like this:
#Bean
public SetterFactory feignHystrixSetterFactory() {
return (target, method) -> {
String groupKey = target.name();
String commandKey = Feign.configKey(target.type(), method);
return HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey( target.type().getSimpleName() ));
};
}
but what's the follow Timeout?
Feign client timeout is similar to ribbon timeout and specifies the properties of httpconnectin but you can define different timeouts for different feignclient.
feign.client.config.bar.readTimeout //this configuration will apply to bar client
feign.client.config.default.readTimeout // this configuration will apply to all feign
How did I found that? if you debug your application and put breakpoints on the following code of RetryableFeignLoadBalancer class:
final Request.Options options;
if (configOverride != null) {
RibbonProperties ribbon = RibbonProperties.from(configOverride);
options = new Request.Options(ribbon.connectTimeout(this.connectTimeout),
ribbon.readTimeout(this.readTimeout));
}
else {
options = new Request.Options(this.connectTimeout, this.readTimeout);
}
you will see these value will be used as properties of HTTPConection.pls have a look at feign.Client class.
connection.setConnectTimeout(options.connectTimeoutMillis());
connection.setReadTimeout(options.readTimeoutMillis());
I am trying to integrate Hystrix javanica into my existing java EJB web application and facing 2 issues with running it.
When I try to invoke following service it always returns response from fallback method and I see that the Throwable object in fallback method has "com.netflix.hystrix.exception.HystrixTimeoutException" exception.
Each time this service is triggered, HystrixCommad and fallback methods are called multiple times around 50 times.
Can anyone suggest me with any inputs? Am I missing any configuration?
I am including following libraries in my project.
project libraries
I have setup my aspect file as follows:
<aspectj>
<weaver options="-verbose -showWeaveInfo"></weaver>
<aspects>
<aspect name="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect"/>
</aspects>
</aspectj>
Here is my config.properties file in META-INF/config.properties
hystrix.command.default.execution.timeout.enabled=false
Here is my rest service file
#Path("/hystrix")
public class HystrixService {
#GET
#Path("clusterName")
#Produces({ MediaType.APPLICATION_JSON })
public Response getClusterName(#QueryParam("id") int id) {
ClusterCmdBean clusterCmdBean = new ClusterCmdBean();
String result = clusterCmdBean.getClusterNameForId(id);
return Response.ok(result).build();
}
}
Here is my bean class
public class ClusterCmdBean {
#HystrixCommand(groupKey = "ClusterCmdBeanGroup", commandKey = "getClusterNameForId", fallbackMethod = "defaultClusterName")
public String getClusterNameForId(int id) {
if (id > 0) {
return "cluster"+id;
} else {
throw new RuntimeException("command failed");
}
}
public String defaultClusterName(int id, Throwable e) {
return "No cluster - returned from fallback:" + e.getMessage();
}
}
Thanks for the help.
If you want to ensure you are setting the property, you can do that explicitly in the circuit annotation itself:
#HystrixCommand(commandProperties = {
#HystrixProperty(name = "execution.timeout.enabled", value = "false")
})
I would only recommend this for debugging purposes though.
Something that jumps out to me is that Javanica uses AspectJ AOP, which I have never seen work with new MyBean() before. I've always have to use #Autowired with Spring or similar to allow proxying. This could well just be something that is new to me though.
If you set a breakpoint inside the getClusterNameForId can you see in the stack trace that its being called via reflection (which it should be AFAIK)?
Note you can remove commandKey as this will default to the method name. Personally I would also remove groupKey and let it default to the class name.
I am currently using Spring 4.1.6 with a RestTemplate to consume a third party webservice with JSON which I cannot change its behavior.I am using Jackson databind v2.6.0.
Problem: Sometimes the service returns for a member a hashmap {member:{"key":"value",...}} sometimes the same member is just an empty array {member:[]}. So I can not ignore the property by default.
Is there a way to configure the deserialization to ignore empty arrays? I saw a jackson property "WRITE_EMPTY_JSON_ARRAYS" but I am not quite sure how I can use it with my restTemplate and spring configuration.
Are there other possiblities e.g. use some combination of #JsonXXX Annotations? I saw #JsonSerialize which can be used on class level, but I don't like to write a deserializer for all my classes just to handle this situation (However if there is no other way of course I will do)
Example responses to llustrate the behavior of the service:
response with a hashmap
{"id":170,"categories":{"13":"caro"}}
response with empty array of the same member
{"id":170,"categories":[]}
Example of my RestTemplate usage:
BasicAuthRequestFactory requestFactory = new BasicAuthRequestFactory(httpClient);
restTemplate = new RestTemplate(requestFactory);
Article a = restTemplate.getForObject(new URI("http://..."), Article.class);
Error:
caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token
at [Source: java.io.PushbackInputStream#4aa21f9d; line: 1, column: 1456] (through reference chain: ResponseArticleWrapper["data"]->Article["categories"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
Example of my current annotated class:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(Include.NON_NULL)
public class Article {
#JsonProperty("id")
private Integer id;
#JsonProperty("categories")
private Map<Integer,String> categories = new HashMap<Integer,String>();
}
Thank you in advance for any hints and examples.
Since jackson-databind 2.5 there is DeserializationFeature for handling this case. It's turned off by default, so you need to configure it in your ObjectMapper:
#Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true);
return objectMapper;
}
You can see how the custom ObjectMapper for RestTemplate is configured here: How can we configure the internal Jackson mapper when using RestTemplate?
After you're done with the configuration, you can just let Spring wire it for you in your class:
#Autowired
private RestOperations restTemplate;
and use the provided restTemplate instance.
I want return a dynamic JSON object from my endpoint, to add properties on the fly without changing any method signature.
It feels rather contrary to the design of endpoints, but I found it very useful to have endpoints that could accept or return arbitrary JSON objects. So I use a class like this in my endpoint method:
public class DataParcel {
public Integer obj_type = -1;
public List<String> json_objects = null; // new ArrayList<String>();
The only complication is which JSON library to use - the JSON encoding/decoding is no longer done for you automatically.
I'm facing following problem:
I'm using CXF for REST services. For exception handling I'm using javax.ws.rs.ext.ExceptionMapper and in public Response toResponse(T ex) I want to return some object, for example
class MyObject {
String detail;
}
example implementation of method is similar to
public Response toResponse(T ex) {
MyObject o = new MyObject();
o.detail = "...";
return Response.status(400).entity(o).build();
}
but I'm having problem
org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor writeResponseErrorMessage
WARNING: No message body writer has been found for response class RequestError.
Somehow I found that when I specify MediaType
return Response.status(400).entity(o).type("application/json").build();
everything is ok, but I do not know which type client accepts...
Of course I can somewhere store which types client accepts and later use the correct one, but this smells. I'd like to use something nicer.
For example in my CXF endpoint I can specify, using #Produces, what kind of MediaTypes my controller method produces and CXF/Spring select the correct one. I tried it in my ExceptionMapper too, but it doesn't work.
u can do it like this
#Context HttpHeaders headers;
public Response toResponse(Exception e) {
ExceptionEntity ee = new ExceptionEntity(e);
ResponseBuilder rb = Response.status(Response.Status.INTERNAL_SERVER_ERROR);
rb.type(headers.getMediaType());
rb.entity(ee);
Response r = rb.build();
return r;
}
i'm using cxf-rs 2.7.5