SpringFox Docket per controller not working in spring boot - api

In my spring boot application, I have multiple Rest Controllers and need to generate swagger for each controller seperately.
By using below Docket config for each controller in my spring boot application class, i am able to download controller specific swagger by going to /v2/api-docs?group=ai where i = 1 to n
However in swagger-ui.html, when i select a1(/v2/api-docs?group=a1), it shows path as "/api/a1/a1", while selecting a2(/v2/api-docs?greoup=a2), it shows correct path i.e. /api/a2
I have tried changing in Docket ,paths regex to absolute e.g. "api/a1" etc but that didn't help.
#Bean
public Docket a1Api() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("a1")
.apiInfo(a1Info())
.select().apis(RequestHandlerSelectors.any())
.paths(regex("/api/a1.*"))
.build()
.pathMapping("/");
}
#Bean
public Docket a2Api() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("a2")
.apiInfo(a1Info())
.select().apis(RequestHandlerSelectors.any())
.paths(regex("/api/a2.*"))
.build()
.pathMapping("/");
}
private ApiInfo a1Info() {
return new ApiInfoBuilder()
.title("a1 Swagger 2.0")
.description("a1")
.license("a1")
.version("1.0")
.build();
}
private ApiInfo a2Info() {
return new ApiInfoBuilder()
.title("a2 Swagger 2.0")
.description("a2")
.license("a2")
.version("1.0")
.build();
}
Rest Controllers
#RestController
#Api(tags = "A1")
#RequestMapping("/api/a1")
public class a1Controller {
#ApiOperation(value = "a1")
#RequestMapping(value = "", method = RequestMethod.POST)
public a1Response invoke(#RequestBody a1Request va1Request) {
.....;
}
}
#RestController
#Api(tags = "An")
#RequestMapping("/api/an")
public class a1Controller {
#ApiOperation(value = "an")
#RequestMapping(value = "", method = RequestMethod.POST)
public anResponse invoke(#RequestBody anRequest vanRequest) {
.....;
}
}
Any idea how can i address this....
i am using springfox swagger version 2.6.1

You can add multiple controller class using following Swagger Configuration:
1) Create a Swagger Configuration Class.
2) Then specify the base package of controllers.
import java.util.Collections;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
#Configuration
#EnableSwagger2
public class SwaggerConfig
{
private static final ApiInfo DEFAULT_API_INFO = null; //Swagger info
#Bean
public Docket api()
{
return new Docket(DocumentationType.SWAGGER_2)
.forCodeGeneration(Boolean.TRUE)
.select()
.apis(RequestHandlerSelectors.basePackage("com.user.controller"))
.paths(PathSelectors.any())
.paths(Predicates.not(PathSelectors.regex("/logout.*")))
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfo(
"REST API",
"REST description of API.",
"API TOS",
"Terms of service",
new Contact("Rajib Garai", "https://www.linkedin.com/in/rajibgarai90/", "90rajibgarai#gmail.com"),
"License of API", "API license URL", Collections.emptyList());
}
}

Here is the code i wrote to find and automatically create Docket on runtime per controller,
also has a Default Docket to show all in one group.
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Autowired
ConfigurableApplicationContext context;
//Default Docket to show all
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(metaData())
.forCodeGeneration(Boolean.TRUE)
.select()
.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
.paths(PathSelectors.any())
.paths(Predicates.not(PathSelectors.regex("/error.*")))
.build();
}
//Creating Docket Dynamically per Rest Controller
#PostConstruct
public void postConstruct() throws ClassNotFoundException {
ClassPathScanningCandidateComponentProvider provider
= new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AnnotationTypeFilter(RestController.class));
for (BeanDefinition beanDef : provider.findCandidateComponents("com.blah.blah.package")) {
Class<?> cl = Class.forName(beanDef.getBeanClassName());
RequestMapping requestMapping = cl.getAnnotation(RequestMapping.class);
if (null != requestMapping && null != requestMapping.value() && requestMapping.value().length > 0) {
String resource_group = requestMapping.value()[0];
SingletonBeanRegistry beanRegistry = context.getBeanFactory();
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.groupName(resource_group)
.apiInfo(metaData())
.forCodeGeneration(Boolean.TRUE)
.select()
//.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
.paths(PathSelectors.regex(resource_group + ".*"))
.paths(Predicates.not(PathSelectors.regex("/error.*")))
.build();
beanRegistry.registerSingleton(cl.getSimpleName() + "_docket_api", docket);
}
}
}
private ApiInfo metaData() {
return new ApiInfoBuilder()
.title("some Title Here")
.description("Some Desciption")
.version("1.0")
.contact(new Contact("Asad Abdin", "", "asadabdin#gmail.com"))
.build();
}

Related

ClientHttpRequestInterceptor not called in springboot

I am trying to add logging to my application using ClientHttpRequestInterceptor.My interceptor is not being called.
Not sure what is going wrong here -
Here is my code -
#Component
#Slf4j
public final class RestTemplateInterceptor implements ClientHttpRequestInterceptor {
protected static final LoggingAspect aspect = new LoggingAspect();
private final RequestContext requestContext;
private boolean logResponseBody = true;
public RestTemplateInterceptor(RequestContext requestContext) {
this.requestContext = requestContext;
}
#Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
populateHeader(request);
traceRequest(request, body);
ClientHttpResponse response = clientHttpRequestExecution.execute(request,body);
traceResponse(response);
return response;
}
private void populateHeader(HttpRequest request) {
final HttpHeaders headers = request.getHeaders();
// Propagate TAM headers
headers.add("iv-user", requestContext.getUser());
headers.add("MessageId", requestContext.getMessageId());
headers.add("CorrelationId", requestContext.getConversationId());
headers.add("BusinessId", requestContext.getBusinessId());
headers.add("ApplicationName", requestContext.getSourceSystem());
headers.add("iv-groups", requestContext.getGroups());
headers.add("MessageDateTime", requestContext.getSourceTimestamp());
}
...................
Here is my config file
#Configuration
public class RestTemplateConfig {
/**
* initialise restTemplate
*
* #param restTemplateInterceptor autowired in RestTemplateInterceptor
* #return
*/
#Bean
public RestTemplate restTemplate(ClientHttpRequestInterceptor restTemplateInterceptor, ObjectMapper objectMapper) {
RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors)) {
interceptors = new ArrayList<>();
}
interceptors.add(restTemplateInterceptor);
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
}
Here is my WebMVC file
#Configuration
public class WebMvcConfig implements WebMvcConfigurer {
#Bean
public WebMvcConfigurer webAuthentication() {
return new WebMvcConfigurer() {
#Override
public void addInterceptors(InterceptorRegistry registry) {
//registry.addInterceptor(myInterceptor());
registry.addInterceptor(new MVCLoggingInterceptor()).addPathPatterns("/api/**");
registry.addInterceptor(new WebAuthentication()).addPathPatterns("/api/**/");
}
};
}
}
Here is my application file
#EnableAsync
#EnableScheduling
#SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
public class XManagementApplication {
public static void main(String[] args) {
SpringApplication.run(XManagementApplication.class, args);
}
}
Can anybody tell why my interceptor class is not called when I try to call any API
Any help would be appreciate?
I don't really understand why you want to instantiate your RestTemplateInterceptor as a Bean. Why not simply instantiate your interceptor inside the method RestTemplateConfig.restTemplate() ?
#Configuration
public class RestTemplateConfig {
#Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors)) {
interceptors = new ArrayList<>();
}
interceptors.add(new RestTemplateInterceptor());
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
}
Btw, why do you need to pass RequestContext to the constructor of your interceptor ?

Spring-security/Grails app - Custom WebSecurity configurations not getting called

My project is based on Grail 2.5.6 and Spring plugins. I'm trying to create a custom auth provider, filter and token extending their respective basic classes.
this.getAuthenticationManager().authenticate(authRequest)
In my filter the authentication manager is always null. So, it throws cannot invoke authenticate() on a null object. When I debug on the authenticationManager, it lists other provider names but my custom one.
Here is my custom web security config
#Configuration
#EnableGlobalMethodSecurity(securedEnabled=true)
public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {
OrbisAuthenticationProvider orbisAuthenticationProvider
public CustomWebSecurityConfig() {
super()
log.debug "configure custom security"
print("configure custom security")
}
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
print("configure method 1")
log.debug "configure method 1"
auth.authenticationProvider(orbisAuthenticationProvider)
}
#Bean(name= BeanIds.AUTHENTICATION_MANAGER)
#Override
AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean()
}
#Bean
OrbisAuthenticationFilter orbisAuthenticationProvider() throws Exception {
log.debug "orbis Authentication provider"
OrbisAuthenticationProvider orbisAuthenticationProvider = new OrbisAuthenticationProvider(authenticationManagerBean())
return orbisAuthenticationProvider
}
#Bean
#Autowired
public OrbisAuthenticationFilter orbisAuthenticationFilter() throws Exception {
print("configure orbis filtr")
OrbisAuthenticationFilter oaf = new OrbisAuthenticationFilter()
oaf.setAuthenticationManager(authenticationManagerBean())
oaf.setFilterProcessesUrl("j_orbis_security_check")
oaf.setUsernameParameter("email")
oaf.setPasswordParameter("password")
oaf.setAuthenticationSuccessHandler(new SavedRequestAwareAuthenticationSuccessHandler()
.setDefaultTargetUrl("/oauth/authorize"))
oaf.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler()
.setDefaultFailureUrl("/loginWithOrbis"))
oaf.afterPropertiesSet()
return oaf
}
}
On debugging, it doesn't look like any of these methods are getting called. The annotations don't seem enough to get picked up. I had tried #ComponentScan too.
Do I have to inject this security config somewhere? How do I get authManager to be available in my filter?
OrbisAuthFilter
class OrbisAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
// #Autowired
OrbisAuthenticationProvider orbisAuthenticationProvider
OrbisAuthenticationFilter() {
super("/j_orbis_security_check")
orbisAuthenticationProvider = new OrbisAuthenticationProvider()
}
void afterPropertiesSet() {
assert authenticationManager != null, 'authenticationManager must be specified'
}
#Override
Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String username = request.getParameter("email")
String password = request.getParameter("password")
String accessCode = request.getParameter("accessCode")
OrbisAuthenticationToken authRequestForAuthentication = new OrbisAuthenticationToken(username, password, accessCode)
// This throws error because getAuthenticationManager returns null
// authRequestForAuthentication = this.getAuthenticationManager.authenticate(authRequestForAuthentication)
//This works if I instantiate the orbis provider object in the constructor
authRequestForAuthentication = this.orbisAuthenticationProvider.authenticate(authRequestForAuthentication)
SecurityContextHolder.getContext().setAuthentication(authRequestForAuthentication)
return authRequestForAuthentication
}
protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
#Override
#Autowired
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
}
OrbisAuthProvider
class OrbisAuthenticationProvider implements AuthenticationProvider {
#Override
Authentication authenticate(Authentication authentication) throws AuthenticationException {
OrbisAuthenticationToken orbisAuth = (OrbisAuthenticationToken) authentication
String username = orbisAuth.principal
String password = orbisAuth.credentials
String orbisAccessCode = orbisAuth.orbisAccessCode
def urlToUse = 'https://coopstatus.neu.edu/sail_api/full.aspx?' + 'ac=' + orbisAccessCode + '&e='+ username + '&p=' + password
HttpClient httpClient = DefaultHttpClient.newInstance()
HttpGet getRequest = new HttpGet(urlToUse)
HttpResponse httpResponse = httpClient.execute(getRequest)
JSONObject orbisResponse = new JSONObject(httpResponse.getEntity().getContent().getText())
// if(orbisResponse.get("IsFound")) {
// //Return error not authenticated
// }
Collection<GrantedAuthority> orbisUserGrantedAuthorities = getLDAPUserAuthorities(orbisResponse.get("Email"))
orbisAuth = new OrbisAuthenticationToken(username, password, orbisAccessCode, orbisUserGrantedAuthorities)
return orbisAuth
}
private Collection<GrantedAuthority> getLDAPUserAuthorities(String username) {
LDAPUserDetails currentLdapUserDetails
try {
currentLdapUserDetails = new LDAPUserDetailsService().loadUserByOrbisUsername(username)
log.debug currentLdapUserDetails
} catch(org.springframework.security.core.userdetails.UsernameNotFoundException e) {
log.error("User " + username + " not found in ldap", e)
}
Collection<GrantedAuthority> authorities = new ArrayList<>()
for (String authority : currentLdapUserDetails.authorities) {
authorities.add(new SimpleGrantedAuthority(authority))
}
return authorities
}
#Override
public boolean supports(Class<?> authentication) {
return (OrbisAuthenticationToken.class
.isAssignableFrom(authentication));
}
}
Resources.groovy
import edu.neu.security.OrbisAuthenticationFilter
import edu.neu.security.OrbisAuthenticationProvider
beans = {
userDetailsService(edu.neu.security.LDAPUserDetailsService)
orbisAuthenticationProvider(OrbisAuthenticationProvider)
orbisAuthenticationFilter(OrbisAuthenticationFilter) {
orbisAuthenticationProvider = ref("orbisAuthenticationProvider")
requiresAuthenticationRequestMatcher = ref('filterProcessUrlRequestMatcher')
// This throws error during startup. Unable to init bean
// authenicationManager = ref("authenicationManager")
}
myOAuth2ProviderFilter(OAuth2ProviderFilters) {
//grailsApplication = ref('grailsApplication')
// properties
}
}
I followed some of the concepts from this project: https://github.com/ppazos/cabolabs-ehrserver/
Even if the whole process is executed and securityContext is set with authenticated, when I hit oauth/authorize to get Authorization_Code, it redirects back to '/login/auth'. It still doesn't know that a user is already authenticated.
When you add an authentication provider to the AuthenticationManagerBuilder bean (which comes from AuthenticationConfiguration), the authentication manager bean you declare is not used.
Try:
#Configuration
#EnableGlobalMethodSecurity(securedEnabled=true)
public class CustomWebSecurityConfig {
OrbisAuthenticationProvider lwoAuthProvider;
public CustomWebSecurityConfig() {
//
}
#Bean(name= BeanIds.AUTHENTICATION_MANAGER)
AuthenticationManager authenticationManagerBean() throws Exception {
return new ProviderManager(Arrays.asList(lwoAuthProvider));
}
Your AuthenticationManager bean should get picked up and will be used for method security. You can also #Autowire it in your filter if it is being managed by Spring, or #Autowire it in the #Configuration class that instantiates your filter.
NOTE: the above class WILL NOT create any of the Spring Security filters.
(The filter chain wasn't being created anyway - you didn't annotate your class with #EnableWebSecurity)

Adding path to base url in Spring Rest Docs?

I have following configuration to use with Rest Docs:
webTestClient = buildWebClient().mutate()
.filter(documentationConfiguration(restDocumentation))
.baseUrl("https://api.my-domain.com/")
.build()
In my case I use path prefix to my service - service/foo since I use k8s ingress and my service is served on path offset.
Is there a way to insert such prefix without modifying production code?
Related documentation fragment:
https://docs.spring.io/spring-restdocs/docs/current/reference/html5/#configuration-uris-webtestclient
To document another URI than the one called to generate documentation, you have to write your own OperationPreprocessor. There are some predefined like Preprocessors.modifyUris but it does not allow to modify the request path.
Check below the webTestClient configuration and the URIUpdaterOperationRequest class. Code is available on GitHub: https://github.com/Query-Interface/SO-Answers/blob/master/java/spring/rest-docs-modify-uripath/src/test/java/com/example/demo/DemoApplicationTests.java
public void init() throws Exception {
final URIUpdaterPreprocessor preprocessor = new URIUpdaterPreprocessor();
webTestClient = webTestClient.mutate()
.filter((documentationConfiguration(this.restDocumentation)
.operationPreprocessors()
.withRequestDefaults(preprocessor)
.withResponseDefaults(prettyPrint()))
)
.build();
}
private static final class URIUpdaterPreprocessor
implements OperationPreprocessor {
#Override
public OperationRequest preprocess(OperationRequest request) {
return new URIUpdaterOperationRequest(request);
}
#Override
public OperationResponse preprocess(OperationResponse response) {
return response;
}
}
private static final class URIUpdaterOperationRequest
implements OperationRequest {
private OperationRequest delegate;
public URIUpdaterOperationRequest(OperationRequest request) {
delegate = request;
}
public byte[] getContent() {
return delegate.getContent();
}
public String getContentAsString() {
return delegate.getContentAsString();
}
public HttpHeaders getHeaders() {
return delegate.getHeaders();
}
public HttpMethod getMethod() {
return delegate.getMethod();
}
public Parameters getParameters() {
return delegate.getParameters();
}
public Collection<OperationRequestPart> getParts() {
return delegate.getParts();
}
public URI getUri() {
URI sourceUri = delegate.getUri();
UriComponentsBuilder builder = UriComponentsBuilder.fromUri(sourceUri);
return builder
.host(sourceUri.getHost())
.replacePath("/service/foo"+sourceUri.getPath())
.build().toUri();
}
public Collection<RequestCookie> getCookies() {
return delegate.getCookies();
}
}
I think another possibilty is to update the mustache templates so as to add a prefix before all request path references. The default templates are located here on github.

Spring Security Basic authentication for a single path next to token authentication

I have a custom ResourceServerTokenServices in place:
#Configuration
public class CloudSecurityConfig {
#Bean
protected MyResourceServerTokenServices() {
return new MyResourceServerTokenServices();
}
}
Then I have follogin ResourceServerConfigurerAdapter:
#Configuration
#EnableWebSecurity
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityResourceConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
http.authorizeRequests().accessDecisionManager(accessDecisionManager())
.antMatchers("/h2-console/**").anonymous()
.antMatchers("/health/**").permitAll()
.antMatchers("/v*/api-docs").permitAll().anyRequest()
.authenticated().and().httpBasic().and().headers()
.frameOptions().disable();
}
#Bean
protected UnanimousBased accessDecisionManager() {
List<AccessDecisionVoter<? extends Object>> voterList = new ArrayList<>();
WebExpressionVoter expressionVoter = new WebExpressionVoter();
expressionVoter.setExpressionHandler(new OAuth2WebSecurityExpressionHandler());
voterList.add(expressionVoter);
voterList.add(new AuthenticatedVoter());
return new UnanimousBased(voterList);
}
}
Now I need to add basic authentication (with inMemory credentials) for one single endpoint (lets say /myEndpoint**). How can I achieve this?
Thanks!

Jackson2 custom deserializer factory

I am porting jackson 1.6 code to jackson 2 and stumbled upon a deprecated code.
What i did in jackson 1.6 is:
CustomDeserializerFactory sf = new CustomDeserializerFactory();
mapper.setDeserializerProvider(new StdDeserializerProvider(sf));
sf.addSpecificMapping(BigDecimal.class, new BigDecimalDeserializer());
t = mapper.readValue(ts, X[].class);
Anyone knows how to do it in jackson 2?
To add a factory--not just a deserializer--don't use SimpleModule. Create your own Module and within it create a Deserializers object that is added to the SetUpContext. The Deserializers object will have access to similar methods that the factory did where you can get extra type information about the deserializer needed.
It will look something like this (note that it doesn't need to be an inner class):
public class MyCustomCollectionModule extends Module {
#Override
public void setupModule(final SetupContext context) {
context.addDeserializers(new MyCustomCollectionDeserializers());
}
private static class MyCustomCollectionDeserializers implements Deserializers {
...
#Override
public JsonDeserializer<?> findCollectionDeserializer(final CollectionType type, final DeserializationConfig config, final BeanDescription beanDesc, final TypeDeserializer elementTypeDeserializer, final JsonDeserializer<?> elementDeserializer) throws JsonMappingException {
if (MyCustomCollection.class.equals(type.getRawClass())) {
return new MyCustomCollectionDeserializer(type);
}
return null;
}
...
}
}
In Jackson 2.0:
Create a Module (usually SimpleModule)
Register custom handlers with it.
Call ObjectMapper.registerModule(module);.
This is available on Jackson 1.x as well (since 1.8 or so).
Here is an example of registering a module (in this case Joda date handling) in Jackson 2.x:
ClientConfig clientConfig = new DefaultClientConfig();
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
JacksonJsonProvider provider = new JacksonJsonProvider();
provider.configure(SerializationFeature.INDENT_OUTPUT, true);
provider.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
provider.setMapper(mapper);
clientConfig.getSingletons().add(provider);
Client client = Client.create(clientConfig);
Exemplifying #StaxMan answer
Basically you need to create a module (SimpleModule), add a deserializer and register this module
final SimpleModule sm = new SimpleModule();
sm.addDeserializer(Date.class, new JsonDeserializer<Date>(){
#Override
public Date deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
try {
System.out.println("from my custom deserializer!!!!!!");
return new SimpleDateFormat("yyyy-MM-dd").parse(p.getValueAsString());
} catch (ParseException e) {
System.err.println("aw, it fails: " + e.getMessage());
throw new IOException(e.getMessage());
}
}
});
final CreationBean bean = JsonUtils.getMapper()
.registerModule(sm)
// .setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
.readValue("{\"dateCreation\": \"1995-07-19\"}", CreationBean.class);
Here a fully example
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
/**
* #author elvis
* #version $Revision: $<br/>
* $Id: $
* #since 8/22/16 8:38 PM
*/
public class JackCustomDeserializer {
public static void main(String[] args) throws IOException {
final SimpleModule sm = new SimpleModule();
sm.addDeserializer(Date.class, new JsonDeserializer<Date>(){
#Override
public Date deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
try {
System.out.println("from my custom deserializer!!!!!!");
return new SimpleDateFormat("yyyy-MM-dd").parse(p.getValueAsString());
} catch (ParseException e) {
System.err.println("aw, it fails: " + e.getMessage());
throw new IOException(e.getMessage());
}
}
});
final CreationBean bean = JsonUtils.getMapper()
.registerModule(sm)
// .setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
.readValue("{\"dateCreation\": \"1995-07-19\"}", CreationBean.class);
System.out.println("parsed bean: " + bean.dateCreation);
}
static class CreationBean {
public Date dateCreation;
}
}