StreamToIteratorWhile.java
/*******************************************************************************
* Copyright (c) 2026 Carsten Hammer.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Carsten Hammer
*******************************************************************************/
package org.sandbox.jdt.internal.corext.fix.helper;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation;
import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
import org.eclipse.text.edits.TextEditGroup;
import org.sandbox.functional.core.model.LoopModel;
import org.sandbox.jdt.internal.common.ReferenceHolder;
import org.sandbox.jdt.internal.corext.fix.UseFunctionalCallFixCore;
/**
* Transformer for converting Stream forEach expressions to iterator-based while-loops.
*
* <p>Transformation: {@code collection.forEach(item -> ...)} → {@code Iterator<T> it = c.iterator(); while (it.hasNext()) { T item = it.next(); ... }}</p>
*
* <p>Uses the ULR pipeline: {@code LoopModelBuilder → LoopModel → ASTIteratorWhileRenderer}.</p>
*
* @see LoopModel
* @see ASTIteratorWhileRenderer
* @see <a href="https://github.com/carstenartur/sandbox/issues/453">Issue #453</a>
* @see <a href="https://github.com/carstenartur/sandbox/issues/549">Issue #549</a>
*/
public class StreamToIteratorWhile extends AbstractFunctionalCall<ASTNode> {
@Override
public void find(UseFunctionalCallFixCore fixcore, CompilationUnit compilationUnit,
Set<CompilationUnitRewriteOperation> operations, Set<ASTNode> nodesprocessed) {
ExpressionHelper.findForEachInvocations(fixcore, compilationUnit, operations, nodesprocessed);
}
@Override
public void rewrite(UseFunctionalCallFixCore useExplicitEncodingFixCore, ASTNode visited,
CompilationUnitRewrite cuRewrite, TextEditGroup group, ReferenceHolder<ASTNode, Object> data)
throws CoreException {
ExpressionHelper.ForEachRewriteInfo info = ExpressionHelper.extractForEachRewriteInfo(visited, cuRewrite.getAST());
if (info == null) {
return;
}
ASTIteratorWhileRenderer renderer = new ASTIteratorWhileRenderer(cuRewrite.getAST(), cuRewrite.getASTRewrite());
renderer.renderWithBodyStatements(info.model(), info.forEachStatement(), info.bodyStatements(), group);
// Add Iterator import
cuRewrite.getImportRewrite().addImport("java.util.Iterator"); //$NON-NLS-1$
}
@Override
public String getPreview(boolean afterRefactoring) {
if (afterRefactoring) {
return """
Iterator<String> it = items.iterator();
while (it.hasNext()) {
String item = it.next();
System.out.println(item);
}
""";
}
return """
items.forEach(item -> System.out.println(item));
""";
}
}