Repository: mapstruct/mapstruct (language: java)

Issue:
NPE when defining mapping to primitive array
### Expected behavior

Obviously this is not supported, but a better error message would be great

### Actual behavior

```
Internal error in the mapping processor: java.lang.NullPointerException: Cannot invoke "javax.lang.model.element.TypeElement.getEnclosedElements()" because "this.typeElement" is null
at org.mapstruct.ap.internal.model.common.Type.hasAccessibleConstructor(Type.java:1341)
at org.mapstruct.ap.internal.model.BeanMappingMethod$Builder.canReturnTypeBeConstructed(BeanMappingMethod.java:771)
at org.mapstruct.ap.internal.model.BeanMappingMethod$Builder.doesNotAllowAbstractReturnTypeAndCanBeConstructed(BeanMappingMethod.java:485)
at org.mapstruct.ap.internal.model.BeanMappingMethod$Builder.build(BeanMappingMethod.java:211)
at org.mapstruct.ap.internal.processor.MapperCreationProcessor.getMappingMethods(MapperCreationProcessor.java:427)
at org.mapstruct.ap.internal.processor.MapperCreationProcessor.getMapper(MapperCreationProcessor.java:188)
at org.mapstruct.ap.internal.processor.MapperCreationProcessor.process(MapperCreationProcessor.java:142)
at org.mapstruct.ap.internal.processor.MapperCreationProcessor.process(MapperCreationProcessor.java:85)
at org.mapstruct.ap.MappingProcessor.process(MappingProcessor.java:400)
at org.mapstruct.ap.MappingProcessor.processMapperTypeElement(MappingProcessor.java:380)
at org.mapstruct.ap.MappingProcessor.processMapperElements(MappingProcessor.java:329)
at org.mapstruct.ap.MappingProcessor.process(MappingProcessor.java:213)
at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:1023)
at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:939)
at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1267)
at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1382)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1234)
at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:916)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:104)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.invocationHelper(JavacTaskImpl.java:152)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:100)
at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:94)
at org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.compileInProcess(JavaxToolsCompiler.java:126)
at org.codehaus.plexus.compiler.javac.JavacCompiler.performCompile(JavacCompiler.java:174)
at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute(AbstractCompilerMojo.java:1134)
at org.apache.maven.plugin.compiler.CompilerMojo.execute(CompilerMojo.java:187)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:126)
at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2(MojoExecutor.java:328)
at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute(MojoExecutor.java:316)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:174)
at org.apache.maven.lifecycle.internal.MojoExecutor.access$000(MojoExecutor.java:75)
at org.apache.maven.lifecycle.internal.MojoExecutor$1.run(MojoExecutor.java:162)
at org.apache.maven.plugin.DefaultMojosExecutionStrategy.execute(DefaultMojosExecutionStrategy.java:39)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:159)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:105)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:73)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:53)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:118)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:261)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:173)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:101)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:906)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:283)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:206)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:283)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:226)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:407)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:348)
```

### Steps to reproduce the problem

Java 17

Define this Mapper interface:

```
@Mapper
public interface TestMapper {
    byte[] map(String something);
}
```

### MapStruct Version

1.6.3


Discussion / hints:
I'm looking in to this, because crashes are indeed not nice.

In case of `byte map(String something)` we already give a message `Can't generate mapping method with primitive return type.`
I guess we can do the same for `byte[] map(String something)` and other primitive types like it.
I think the message would be something like `Can't generate mapping method with primitive array return type.`

Working on a PR to implement this check.

Fix patch:
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java
index 2c8ad5dcb9..c8c13e6bf9 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java
@@ -555,6 +555,11 @@ private boolean checkParameterAndReturnType(ExecutableElement method, List<Param
                 return false;
             }
 
+            if ( !parameterType.isIterableOrStreamType() && resultType.isArrayType() ) {
+                messager.printMessage( method, Message.RETRIEVAL_NON_ITERABLE_TO_ARRAY );
+                return false;
+            }
+
             if ( parameterType.isPrimitive() ) {
                 messager.printMessage( method, Message.RETRIEVAL_PRIMITIVE_PARAMETER );
                 return false;
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java b/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java
index 5887ee07f0..221aed2859 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java
@@ -175,6 +175,7 @@ public enum Message {
     RETRIEVAL_ITERABLE_TO_NON_ITERABLE( "Can't generate mapping method from iterable type from java stdlib to non-iterable type." ),
     RETRIEVAL_MAPPING_HAS_TARGET_TYPE_PARAMETER( "Can't generate mapping method that has a parameter annotated with @TargetType." ),
     RETRIEVAL_NON_ITERABLE_TO_ITERABLE( "Can't generate mapping method from non-iterable type to iterable type from java stdlib." ),
+    RETRIEVAL_NON_ITERABLE_TO_ARRAY( "Can't generate mapping method from non-iterable type to array." ),
     RETRIEVAL_PRIMITIVE_PARAMETER( "Can't generate mapping method with primitive parameter type." ),
     RETRIEVAL_PRIMITIVE_RETURN( "Can't generate mapping method with primitive return type." ),
     RETRIEVAL_TYPE_VAR_SOURCE( "Can't generate mapping method for a generic type variable source." ),


Test patch:
diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_3786/ErroneousByteArrayMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_3786/ErroneousByteArrayMapper.java
new file mode 100644
index 0000000000..abf84f8228
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_3786/ErroneousByteArrayMapper.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright MapStruct Authors.
+ *
+ * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
+ */
+package org.mapstruct.ap.test.bugs._3786;
+
+import org.mapstruct.Mapper;
+
+@Mapper
+public interface ErroneousByteArrayMapper {
+    byte[] map( String something );
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_3786/Issue3786Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_3786/Issue3786Test.java
new file mode 100644
index 0000000000..bd71392c30
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_3786/Issue3786Test.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright MapStruct Authors.
+ *
+ * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
+ */
+package org.mapstruct.ap.test.bugs._3786;
+
+import org.mapstruct.ap.testutil.IssueKey;
+import org.mapstruct.ap.testutil.ProcessorTest;
+import org.mapstruct.ap.testutil.WithClasses;
+import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
+import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
+import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
+
+/**
+ * @author Ben Zegveld
+ */
+@IssueKey( "3786" )
+public class Issue3786Test {
+
+    @WithClasses( ErroneousByteArrayMapper.class )
+    @ProcessorTest
+    @ExpectedCompilationOutcome(
+        value = CompilationResult.FAILED,
+        diagnostics = {
+            @Diagnostic(
+                type = ErroneousByteArrayMapper.class,
+                kind = javax.tools.Diagnostic.Kind.ERROR,
+                line = 12,
+                message = "Can't generate mapping method from non-iterable type to array."
+            )
+        }
+    )
+    void byteArrayReturnTypeShouldGiveInaccessibleContructorError() {
+    }
+}