-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
PR to support Model enhancements #2056
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made it a PR so we can add comments etc. I added some initial thoughts. I feel like the plugin still needs some tweaking. Let me know what you think?
|
||
public Optional<ResolvedType> extractProjection(ResolvedType type, List<Annotation> annotations, DocumentationType documentationType) { | ||
ModelProjectionProviderPlugin selected = | ||
modelProjectionProviders.getPluginFor(documentationType, new JacksonJsonViewProjectionProvider()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if there are plugin extensibility's we should use all of them not just the first one. That way we can layer information via plugins.
} | ||
|
||
@Override | ||
public Optional<Class<?>> projectionFor(ResolvedType type, List<Annotation> typeAnnotations) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should return a ResolvedType
IMO.
Also have you thought about how we might influence a projection not using annotations (I don't know how gson handles this)? I think it might be a good idea to extract a parameter object i.e. projection context that gives it access to/or parts of the RequestMappingContext
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh never mind... I see what this is doing. I don't think this interface is accurate. I'm thinking of the return value as an alternate type for the type
. This makes this interface is jackson specific and will not work for spring-data-rest I think.
I was thinking more in these terms. Lets take this example from here
public class Views {
public static class Public {
}
public static class Internal extends Public {
}
}
public class Item {
@JsonView(Views.Public.class)
public int id;
@JsonView(Views.Public.class)
public String itemName;
@JsonView(Views.Internal.class)
public String ownerName;
}
I would think that this interface would behave something like this.
//Pseudo code on how this should be used.
ProjectionContext context = new ProjectionContext(
type, //Type to find a projection type
annotations, //Annotations to help finding projections
... more params as needed
);
JacksonJsonViewProjectionProvider plugin = createInstanceOfPlugin();
Optional<ResolvedType> projection = instance.projectionFor(context);
//OR
Optional<Model> projection = instance.projectionFor(context);
Here projection would be a either a in-memory ResolvedType
of type ItemPublicView
built using AlternateTypeBuilder or straight away building the Model object via the ModelBuilder
, that has the public properties as we do here. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As i know, Gson does not have full projection support. Just only SerializationStrategy
to determine which properties will be serialized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a method Optional <Class<?> getRequiredAnnotation()
that will handle case with JsonView, and will be ignored in case of Spring Data Rest
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And we might have a case, where there won't be any projection, just all Class... For example, no defined @Projection
classes, or no @JSONVIEW annotation on field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dilip, that is outdated code....
@Override
public List<ResolvedType> projectionsFor(ResolvedType type, Optional<? extends Annotation> requiredAnnotation) {
List<Class<?>> projections = newArrayList();
if (requiredAnnotation.isPresent() &&
requiredAnnotation.get() instanceof JsonView) {
projections = newArrayList(((JsonView)requiredAnnotation.get()).value());
}
return from(projections).transform(toResolvedType()).toList();
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In last commit I changed interface and implementation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agreed, ProjectionContext
is a good idea, to consolidate all required information to determine projection
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But, for me Projection is ONLY a part of ModelContext
, just additional information, to determine which properties must be serialized or deserialized.
@@ -187,6 +187,10 @@ public String getGroupName() { | |||
public <T extends Annotation> Optional<T> findControllerAnnotation(Class<T> annotation) { | |||
return handler.findControllerAnnotation(annotation); | |||
} | |||
|
|||
public List<Annotation> getAnnotations() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the findControllerAnnotation
findAnnotations
not work? I feel like a plugin should request only annotations it knows about. This is very open interface in my opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've deleted that already. The main idea is to make common interface to handle all cases with projections.
@@ -114,6 +116,11 @@ public String getName() { | |||
} | |||
|
|||
@Override | |||
public List<Annotation> getAnnotations() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here... I feel like a plugin should request only annotations it knows about. This is very open interface in my opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, last commit restored that.
@@ -0,0 +1 @@ | |||
/OperationResponseClassReader.java |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
???
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something wrong, I accidentally ignored.... I will fix it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
|
||
import springfox.documentation.spi.DocumentationType; | ||
|
||
public interface ProjectionProviderPlugin extends Plugin<DocumentationType> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this plugin shouldn have something other thanDocumentationType
as the discriminator. It should be something like ProjectionType
which can have one of the following types
- Jackson
- Spring-Data-Rest
- Something we haven't thought off.
Then we can select the right plugin rather than pick the first one the pluginManager finds.Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For that we should have some explicit configuration. Any way we won't have all plugins at one time. So, JacksonJsonViewPlugin
has the lowest priority. If Spring-Data-Rest is included in classpath it will overwrites with its own plugin with higher priority. And custom plugin has the highest priority will overwrite all plugins.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ProjectionType
- will be auto configurable. And Spring-Data-Rest will rewrite it with it's name. But I think it is better to overwrite all plugin, and use priority then to use the configuration plugin name.
* @param annotation - projections of type | ||
* @return resolved projection names | ||
*/ | ||
boolean applyProjection(ResolvedType activeProjection, ResolvedType typeToApply, List<ResolvedType> typeProjections); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not understand this method. I'll bring up the code and take a look at it again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Override
public boolean applyProjection(ResolvedType activeProjection, ResolvedType typeToApply,
Optional<? extends Annotation> requiredAnnotation) {
final Class<?> activeView = activeProjection.getErasedType();
if (requiredAnnotation.isPresent() &&
requiredAnnotation.get() instanceof JsonView &&
activeView != null) {
final Class<?>[] typeProjections = ((JsonView)requiredAnnotation.get()).value();
int i = 0, len = typeProjections.length;
for (; i < len; ++i) {
if (typeProjections[i].isAssignableFrom(activeView)) {
return true;
}
}
}
return false;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Determine if class field belongs to given projection or not
Ok. Waiting for that. |
wait for this fix |
Hey, we would highly appreciate such an improvement as fast as possible. (Currently we have to deploy each Service-Model resulting in a name clash on separate instances (for e.g. breaking changes, Openshift-Projects), which is not what we really want for operational reasons.) |
@phirzel |
what happened |
I've pushed changes. Still a few questions remains opened. |
@MaksimOrlov thank you! thank you! thank you! for working on this! 🙇 For all of you waiting for this feature, please provide us feedback. |
Hi, Was having weird bugs since yesterday, untill I realized the snapshot version has changed! (the good and bad of working with snapshots) I wasn't able to easily make a simple project to exemplify this.. but if you need I can try. Thanks for new developments either way! Regards |
@joao-rebel, thanks for the reporting the issue. |
Hi, Follows the snippet of my code: RestController:
Docklet:
the ObjectA, aka the MultiLangTranslation:
The Translation:
and the HexId:
Since my Service had 3 methods I was getting the Translation and the MultiLangTranslation repeated 3 times. But! This also happened for other services where the principal objects didn't extended from Map, but instead referenced directly or indirectly this MultiLangTranslation. Also for another service where the returns were only: Mono<Map<HexId, List>> is only generated one HexId model, but it didn't allow to make the directModelSubstitute(HexId.class, HexIdModel.class), as it would throw an exception saying that HexId would have been already registered. Sory for the huge information, hope it can help.. |
@joao-rebelo thanks a lot for this infromation, Could you please add the generated json schema file. And could you, please, provide full code listing for Translation class with getters and setter. As I can see class HexId is not symmetric (difference between getters and setters). So for serialization and deserialization will be generated two different models. |
Follows the translation. I believe it is symmetric.
The generated doc: |
Ok. |
#Model enhancements include
Part of a different effort (these are different concepts) edited
2017-10-07 10:51:59