Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jsondoc examples does not use settings from springs ObjectMapper #42

Closed
ST-DDT opened this issue Sep 29, 2017 · 6 comments
Closed

Jsondoc examples does not use settings from springs ObjectMapper #42

ST-DDT opened this issue Sep 29, 2017 · 6 comments
Labels

Comments

@ST-DDT
Copy link

ST-DDT commented Sep 29, 2017

The issue

The example generated by jsondoc does match the settings that have been set on the Jackson2HttpMessageConverter.

objectMapper.findAndRegisterModules()
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
...

I don't know how the template is generated, so I cannot give you further hints how to fix this.
If you give me a pointer where/how they are generated I might be able to present a solution.

Livedoc output

{
  "name": "",
  "startupTime": {
    "year": 0,
    "month": "JANUARY",
    "dayOfMonth": 0,
    "dayOfWeek": "MONDAY",
    "dayOfYear": 0,
    "monthValue": 0,
    "nano": 0,
    "hour": 0,
    "minute": 0,
    "second": 0,
    "chronology": {
      "calendarType": "",
      "id": ""
    }
  },
  "currentTime": {
    "year": 0,
    "month": "JANUARY",
    "dayOfMonth": 0,
    "dayOfWeek": "MONDAY",
    "dayOfYear": 0,
    "monthValue": 0,
    "nano": 0,
    "hour": 0,
    "minute": 0,
    "second": 0,
    "chronology": {
      "calendarType": "",
      "id": ""
    }
  }
}

Expected output

{
  "name": "",
  "startupTime": "2017-03-01T13:37:00Z",
  "currentTime": "2017-03-01T13:37:00Z"
}
@joffrey-bion
Copy link
Owner

joffrey-bion commented Sep 29, 2017

Hi @ST-DDT , once again thanks for your feedback, it's always very constructive and useful.

There are basically 2 steps in template generation:

  • create some sort of default Java object of the given type
  • serialize it to JSON with the rest of the docs

What I've changed so far resides in the Java objects creation. Jsondoc can only read Java fields to find properties, while Livedoc reads the properties returned by the configured PropertyScanner that is also used for the doc generation (which can be customized and could be anything).
When using livedoc-springmvc and its SpringLivedocReaderFactory, the PropertyScanner is a JacksonPropertyScanner that I create using Spring's ObjectMapper, so it respects your Jackson annotations, and most of the configuration (@JsonIgnore, custom property names etc.).

This Java objects creation is done in the TemplateProvider. The serialization to a JSON string from these objects happens when serializing the big Livedoc object at the moment you request it from the controller, which means that these objects should be serialized using the Spring Jackson2HttpMessageConverter used for the /jsondoc endpoint. Which is why I'm surprised it's inconsistent with your settings.

I didn't change the serialization of the doc AFAIR, and the only thing that comes to my mind so far is the fact that I changed the type of the template field from ObjectTemplate (which extended LinkedHashMap) to a plain Java Object.

I'll look into this issue ASAP.

@joffrey-bion
Copy link
Owner

Hi @ST-DDT , I've got a couple questions to investigate this issue:

  1. How do you use livedoc-springmvc? Do you create your own controller?
  2. Do you create your own LivedocReader?
  3. Does your first sentence mean you are seeing your expected result with the original Jsondoc project but not with Livedoc?
  4. How/where/when do you configure the ObjectMapper used by Spring's Jackson2HttpMessageConverter?

@ST-DDT
Copy link
Author

ST-DDT commented Sep 29, 2017

  1. How do you use livedoc-springmvc? Do you create your own controller?
@Bean
public JsonLivedocController documentationController() {
	String version = getCurrentVersion();
	String contextPath = getContextPath();
	List<String> packages = Arrays.asList("a", "b", "c");
	return new JsonLivedocController(version, contextPath, packages);
}

No other configuration for LiveDocs.

  1. Do you create your own LivedocReader?

I don't understand the question, but I guess I don't.

  1. Does your first sentence mean you are seeing your expected result with the original Jsondoc project but not with Livedoc?

No, I don't get the expected result with JsonDoc either. IIRC I get the following from JsonDoc:

{
    "currentTime": { },
    "name": "",
    "startupTime": { }
}
  1. How/where/when do you configure the ObjectMapper used by Spring's Jackson2HttpMessageConverter?
@Configration
public class MyWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {

	@Override
	public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
		for (HttpMessageConverter<?> converter : converters) {
			if (converter instanceof AbstractJackson2HttpMessageConverter) {
				((AbstractJackson2HttpMessageConverter) converter).getObjectMapper().disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
			}
		}
	}

}

@joffrey-bion
Copy link
Owner

joffrey-bion commented Sep 29, 2017

Thanks a lot for your answers.

Do you create your own LivedocReader?

I don't understand the question, but I guess I don't.

This was in fact answered by question 1. There is another JsonLivedocController constructor taking a custom LivedocReader object for the doc generation, but you used the usual one taking a package list. The constructor that you used creates a Spring-oriented LivedocReader, which is what we want here, so no issue on that side.
FYI, in the next version of Livedoc, due to the fix of #12, neither constructors will take the basePath as an argument, as it is now inferred by default from the current request context. You will still be able to force it via a setter of course.

Does your first sentence mean you are seeing your expected result with the original Jsondoc project but not with Livedoc?

No, I don't get the expected result with JsonDoc either.

Thanks for the clarification, I was really wondering how on earth this behaviour could have changed.

Regarding your ObjectMapper configuration, can you confirm this configuration is actually applied to your other endpoints? Does your API actually return dates in text format?
I would just like to confirm whether this instanceof check is actually true at some point.

@joffrey-bion
Copy link
Owner

joffrey-bion commented Sep 29, 2017

Ok, I guess I have found the issue.

In fact, Livedoc doesn't use the actual ObjectMapper instance used by Spring, but simply a Spring-generated ObjectMapper instance. Therefore, it cannot reflect any custom configuration.

I had written it this way temporarily, but I thought I had changed it to access the actual ObjectMapper bean. I guess I was wrong.

The culprit is the SpringLivedocReaderFactory:

public class SpringLivedocReaderFactory {

    public static LivedocReader getReader(List<String> packages) {
        Reflections reflections = LivedocUtils.newReflections(packages);
        AnnotatedTypesFinder annotatedTypesFinder = LivedocUtils.createAnnotatedTypesFinder(reflections);

        PropertyScanner propertyScanner = createJacksonPropertyScanner();
        DocReader springDocReader = new SpringDocReader(annotatedTypesFinder);
        DocReader baseDocReader = new LivedocAnnotationDocReader(annotatedTypesFinder);

        return new LivedocReaderBuilder().scanningPackages(packages)
                                         .withPropertyScanner(propertyScanner)
                                         .addDocReader(springDocReader)
                                         .addDocReader(baseDocReader)
                                         .build();
    }

    private static PropertyScanner createJacksonPropertyScanner() {
        // to match the spring config without accessing the actual bean containing it
        ObjectMapper jacksonObjectMapper = Jackson2ObjectMapperBuilder.json().build();
        return new JacksonPropertyScanner(jacksonObjectMapper);
    }
}

@joffrey-bion
Copy link
Owner

joffrey-bion commented Sep 29, 2017

Closing this issue as it contains 2 different issues: #43 and #44

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Development

No branches or pull requests

2 participants