Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Optional<Map> / Optional<Collection> source property generates unguarded Optional#get, throwing NoSuchElementException when empty

オープン
#4,111 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
72/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
静か
技術スタック
java
領域
devtools

調査の方向性

示されている javac コマンドを使用して Source.java、Target.java、SourceMapper.java、Demo.java で問題を再現し、その後、生成された SourceMapperImpl.java を調べる。保護されたスカラー処理と照らし合わせて、map と collection の処理を追跡する。Optional と Optional の空の値が NoSuchElementException なしでマッピングされ、関連するリグレッションカバレッジが通れば完了とする。

索引モデルが issue の本文から書いたものです。

説明

Expected behavior

When a source property is Optional<T>, the generated mapper should read the value only when it is present — as it already does for scalar types:

if ( source.getName().isPresent() ) {
    name = source.getName().get();
}
Actual behavior

For Optional<Map<K, V>> and Optional<List<E>> source properties the presence check is omitted and Optional#get is called unconditionally, so mapping a source whose Optional is empty throws NoSuchElementException.

Generated mapper (note the scalar property in the same method is guarded):

@Override
public Target toTarget(Source source) {
    if ( source == null ) {
        return null;
    }

    String name = null;
    Map<String, String> attributes = null;
    List<String> tags = null;

    if ( source.getName().isPresent() ) {
        name = source.getName().get();
    }
    attributes = source.getAttributes().get();   // no presence check
    tags = source.getTags().get();               // no presence check

    Target target = new Target( name, attributes, tags );

    return target;
}

Runtime, mapping a Source whose three properties are all Optional.empty():

Exception in thread "main" java.util.NoSuchElementException: No value present
	at java.base/java.util.Optional.get(Optional.java:143)
	at repro.SourceMapperImpl.toTarget(SourceMapperImpl.java:27)
	at Demo.main(Demo.java:9)

The inconsistency between the scalar and the map/collection properties in the same generated method suggests the presence check is lost on the branch that handles map and collection types.

This makes Optional-returning getters unusable in practice for map and collection properties, since an absent value is exactly the case Optional exists to express.

Related to #3976, but that one concerns get() vs orElseThrow(); here the presence check is missing altogether.

Steps to reproduce the problem

Source.java:

package repro;

import java.util.List;
import java.util.Map;
import java.util.Optional;

public class Source
{
    private final Optional<String> name;
    private final Optional<Map<String, String>> attributes;
    private final Optional<List<String>> tags;

    public Source( Optional<String> name, Optional<Map<String, String>> attributes, Optional<List<String>> tags )
    {
        this.name = name;
        this.attributes = attributes;
        this.tags = tags;
    }

    public Optional<String> getName()
    {
        return name;
    }

    public Optional<Map<String, String>> getAttributes()
    {
        return attributes;
    }

    public Optional<List<String>> getTags()
    {
        return tags;
    }
}

Target.java:

package repro;

import java.util.List;
import java.util.Map;

public record Target( String name, Map<String, String> attributes, List<String> tags )
{ }

SourceMapper.java:

package repro;

import org.mapstruct.Mapper;

@Mapper
public interface SourceMapper
{
    Target toTarget( Source source );
}

Demo.java:

import java.util.Optional;
import repro.*;

public class Demo
{
    public static void main( String[] args )
    {
        Source source = new Source( Optional.empty(), Optional.empty(), Optional.empty() );
        System.out.println( new SourceMapperImpl().toTarget( source ) );
    }
}

Compiled with plain javac (no build tool, no other annotation processors):

javac -cp mapstruct-1.7.0.Beta2.jar \
      -processorpath mapstruct-processor-1.7.0.Beta2.jar:mapstruct-1.7.0.Beta2.jar \
      -s gen -d out src/repro/*.java

Also reproduces with nullValueMapMappingStrategy = RETURN_NULL and with nullValueCheckStrategy = ALWAYS.

MapStruct Version

1.7.0.Beta2, Java 25.0.4 (Eclipse Adoptium), javac.

主要言語
Java
スター
7.7k
フォーク
1.1k
PR マージ指標
30日以内にマージされた PR はありません

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

mapstruct/mapstruct のほかの issue

mapstruct/mapstruct の issue をすべて見る

似ている issue

Java の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。