Skip to content

Support complex generic type response mapping procesing #150

Open

Description

@MetallFoX

Hi @hauner!

Processing response mapping of generic types with depth 1 works fine:

FooToBar => java.util.Map<java.lang.String, java.lang.String>
FooToBar => java.util.Map<java.lang.String,  java.lang.List>

But it doesn't work with a complex generic types such as:

FooToBar => java.util.Map<java.lang.String, java.lang.List<java.lang.String>>

The output of processing:

line 1:64 no viable alternative at input 'java.util.Map<java.lang.String,java.lang.List<'
processing failed!
io.openapiprocessor.core.processor.mapping.v2.parser.antlr.MappingException: failed to parse mapping: FooToBar => java.util.Map<java.lang.String, java.lang.List<java.lang.String>>
	at io.openapiprocessor.core.processor.mapping.v2.parser.antlr.ParserKt.parseMapping(Parser.kt:27)
	at io.openapiprocessor.core.processor.mapping.v2.MappingConverter.convertType(MappingConverter.kt:91)
	at io.openapiprocessor.core.processor.mapping.v2.MappingConverter.convert(MappingConverter.kt:44)
	at io.openapiprocessor.core.processor.MappingConverter.convert(MappingConverter.kt:29)
	at io.openapiprocessor.core.converter.OptionsConverter.readMapping(OptionsConverter.kt:69)
	at io.openapiprocessor.core.converter.OptionsConverter.convertOptions(OptionsConverter.kt:34)
	at io.openapiprocessor.spring.processor.SpringProcessor.convertOptions(SpringProcessor.kt:116)
	at io.openapiprocessor.spring.processor.SpringProcessor.run(SpringProcessor.kt:45)
	at io.openapiprocessor.gradle.OpenApiProcessorWorker.run(OpenApiProcessorWorker.java:36)
	at io.openapiprocessor.gradle.OpenApiProcessorWorker.execute(OpenApiProcessorWorker.java:25)
	at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
	at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:49)
	at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:43)
	at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:97)
	at org.gradle.workers.internal.AbstractClassLoaderWorker.executeInClassLoader(AbstractClassLoaderWorker.java:43)
	at org.gradle.workers.internal.IsolatedClassloaderWorker.run(IsolatedClassloaderWorker.java:49)
	at org.gradle.workers.internal.IsolatedClassloaderWorker.run(IsolatedClassloaderWorker.java:30)
	at org.gradle.workers.internal.IsolatedClassloaderWorkerFactory$1.lambda$execute$0(IsolatedClassloaderWorkerFactory.java:57)
	at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
	at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
	at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
	at org.gradle.workers.internal.IsolatedClassloaderWorkerFactory$1.execute(IsolatedClassloaderWorkerFactory.java:49)
	at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$2(DefaultWorkerExecutor.java:205)
	at java.base@18.0.1.1/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:187)
	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:120)
	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:162)
	at org.gradle.internal.Factories$1.create(Factories.java:31)
	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:270)
	at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:119)
	at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:124)
	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:157)
	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:126)
	at java.base@18.0.1.1/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
	at java.base@18.0.1.1/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
	at java.base@18.0.1.1/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base@18.0.1.1/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base@18.0.1.1/java.lang.Thread.run(Thread.java:833)
Caused by: io.openapiprocessor.core.processor.mapping.v2.parser.antlr.MappingParserException: no viable alternative at input 'java.util.Map<java.lang.String,java.lang.List<'
	at io.openapiprocessor.core.processor.mapping.v2.parser.antlr.MappingErrorListener.syntaxError(MappingErrorListener.kt:22)
	at org.antlr.v4.runtime.ProxyErrorListener.syntaxError(ProxyErrorListener.java:41)
	at org.antlr.v4.runtime.Parser.notifyErrorListeners(Parser.java:544)
	at org.antlr.v4.runtime.DefaultErrorStrategy.reportNoViableAlternative(DefaultErrorStrategy.java:310)
	at org.antlr.v4.runtime.DefaultErrorStrategy.reportError(DefaultErrorStrategy.java:136)
	at io.openapiprocessor.core.processor.mapping.v2.parser.antlr.MappingParser.targetType(MappingParser.java:524)
	at io.openapiprocessor.core.processor.mapping.v2.parser.antlr.MappingParser.map(MappingParser.java:276)
	at io.openapiprocessor.core.processor.mapping.v2.parser.antlr.MappingParser.mapping(MappingParser.java:154)
	at io.openapiprocessor.core.processor.mapping.v2.parser.antlr.ParserKt.parseMapping(Parser.kt:22)
	... 47 more
Caused by: org.antlr.v4.runtime.NoViableAltException
	at org.antlr.v4.runtime.atn.ParserATNSimulator.noViableAlt(ParserATNSimulator.java:2031)
	at org.antlr.v4.runtime.atn.ParserATNSimulator.execATN(ParserATNSimulator.java:470)
	at org.antlr.v4.runtime.atn.ParserATNSimulator.adaptivePredict(ParserATNSimulator.java:396)
	at io.openapiprocessor.core.processor.mapping.v2.parser.antlr.MappingParser.targetType(MappingParser.java:510)
	... 50 more
Caused by: io.openapiprocessor.core.processor.mapping.v2.parser.antlr.MappingParserException: no viable alternative at input 'java.util.Map<java.lang.String,java.lang.List<'

Caused by: org.antlr.v4.runtime.NoViableAltException


Execution failed for task '...:processSpring'.
> A failure occurred while executing io.openapiprocessor.gradle.OpenApiProcessorWorker
   > failed to parse mapping: FooToBar => java.util.Map<java.lang.String, java.lang.List<java.lang.String>>

It would be useful to add complex generic types support.

Activity

  1. MetallFoX commented on Dec 13, 2022

    @MetallFoX
    Author

    According to swagger reference to openapi specification, the correct way to define Dictionary or Map is to specify additionalProperties section.

    SpringDoc annotation processing generates something like this for the Map<String, List<String>> too:

      /foo/bar:
        get:
          tags:
            - foo
            - bar
          summary: foobar
          responses:
            '200':
              description: OK
              content:
                '*/*':
                  schema:
                    type: object
                    additionalProperties:
                      type: array
                      items:
                        type: string
    

    I've tried several definitions with no result and didn't find additionalProperties handling in the code either.

    It might be better to add additionalProperties support instead of using custom mapping workarounds for such cases.

  2. hauner commented on Dec 14, 2022

    @hauner
    Member

    at the moment, only one level of generic is supported in the mapping (I think it is in the docs). I didn't spent any time yet to find out what it would take to support more levels.

  3. hauner commented on Dec 14, 2022

    @hauner
    Member

    yes, there is no code that checks additionalProperties. So let's make this a feature request :-)

  4. added 3 commits that reference this issue on Dec 30, 2022
  5. added 2 commits that reference this issue on Jan 15, 2023
  6. added this to the 2023.2 milestone on May 7, 2023
  7. added a commit that references this issue on May 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions