Index: applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/replacegeometry/ReplaceGeometryUtils.java
===================================================================
--- applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/replacegeometry/ReplaceGeometryUtils.java	(revision 35616)
+++ applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/replacegeometry/ReplaceGeometryUtils.java	(revision 35617)
@@ -16,4 +16,5 @@
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import javax.swing.JOptionPane;
@@ -155,5 +156,5 @@
             } else if (referenceObject instanceof Relation) {
                 for (RelationMember member : ((Relation) referenceObject).getMembers()) {
-                    if ((member.getRole().equals("outer") || member.getRole().equals("inner"))
+                    if (("outer".equals(member.getRole()) || "inner".equals(member.getRole()))
                             && member.isWay()) {
                         // TODO: could consider more nodes, such as nodes that are members of other ways,
@@ -165,5 +166,9 @@
                 assert false;
             }
-            nodeToReplace = findNearestNode(subjectNode, nodePool);
+            // see #8396: first try to find nearest new node
+            nodeToReplace = findNearestNode(subjectNode, nodePool.stream().filter(Node::isNew).collect(Collectors.toList()));
+            if (nodeToReplace == null) {
+            	nodeToReplace = findNearestNode(subjectNode, nodePool);
+            }
         }
 
@@ -251,5 +256,5 @@
      * @param subjectWay way to modify
      * @param referenceWay way to remove
-     * @return
+     * @return Command to replace geometry or null if user cancelled
      */
     public static ReplaceGeometryCommand buildReplaceWayCommand(Way subjectWay, Way referenceWay) {
@@ -291,7 +296,7 @@
         int gLen = geometryPool.size();
         int nLen = nodePool.size();
-        int N = Math.max(gLen, nLen);
+        int maxDim = Math.max(gLen, nLen);
         boolean useRobust = Config.getPref().getBoolean("utilsplugin2.replace-geometry.robustAssignment", true)
-                && N <= Config.getPref().getInt("utilsplugin2.replace-geometry.robustAssignment.max-size", 300);
+                && maxDim <= Config.getPref().getInt("utilsplugin2.replace-geometry.robustAssignment.max-size", 300);
 
         // Find new nodes that are closest to the old ones, remove matching old ones from the pool
@@ -300,7 +305,7 @@
         if (gLen > 0 && nLen > 0) {
             if (useRobust) {  // use robust, but slower assignment
-                double[][] cost = new double[N][N];
-                for (int i = 0; i < N; i++) {
-                    for (int j = 0; j < N; j++) {
+                double[][] cost = new double[maxDim][maxDim];
+                for (int i = 0; i < maxDim; i++) {
+                    for (int j = 0; j < maxDim; j++) {
                         cost[i][j] = Double.MAX_VALUE;
                     }
@@ -321,5 +326,5 @@
                 try {
                     assignment = new AssignmentProblem(cost);
-                    for (int i = 0; i < N; i++) {
+                    for (int i = 0; i < maxDim; i++) {
                         int nIdx = i;
                         int gIdx = assignment.sol(i);
@@ -369,6 +374,6 @@
 
         // Move old nodes to new positions
-        for (Node node : nodeAssoc.keySet()) {
-            commands.add(new MoveCommand(nodeAssoc.get(node), node.getCoor()));
+        for (Map.Entry<Node, Node> entry : nodeAssoc.entrySet()) {
+            commands.add(new MoveCommand(entry.getValue(), entry.getKey().getCoor()));
         }
 
@@ -394,5 +399,5 @@
      * @return list of distinct nodes that are not tagged and not used anywhere except in the way
      */
-    protected static List<Node> getUnimportantNodes(Way way) {
+    static List<Node> getUnimportantNodes(Way way) {
         List<Node> nodePool = new LinkedList<>();
         for (Node n : way.getNodes()) {
@@ -410,5 +415,5 @@
      * role membership), and thus cannot be safely modified.
      */
-    protected static boolean hasImportantNode(Way geometry, Way way) {
+    static boolean hasImportantNode(Way geometry, Way way) {
         for (Node n : way.getNodes()) {
             // if original and replacement way share a node, it's safe to replace
@@ -429,22 +434,14 @@
     }
 
-    protected static boolean hasInterestingKey(OsmPrimitive object) {
-        for (String key : object.getKeys().keySet()) {
-            if (!OsmPrimitive.isUninterestingKey(key)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    protected static boolean isInArea(Node node, Area area) {
+    static boolean hasInterestingKey(OsmPrimitive object) {
+        return object.getKeys().keySet().stream().anyMatch(k -> !OsmPrimitive.isUninterestingKey(k));
+    }
+
+    static boolean isInArea(Node node, Area area) {
         LatLon ll = node.getCoor();
-        if (node.isNewOrUndeleted() || area == null || ll == null || area.contains(ll.getX(), ll.getY())) {
-            return true;
-        }
-        return false;
-    }
-
-    protected static boolean isInArea(Way way, Area area) {
+        return node.isNewOrUndeleted() || area == null || ll == null || area.contains(ll.getX(), ll.getY());
+    }
+
+    static boolean isInArea(Way way, Area area) {
         if (area == null) {
             return true;
@@ -469,5 +466,5 @@
      * @throws UserCancelException If the user cancelled a dialog.
      */
-    protected static List<Command> getTagConflictResolutionCommands(OsmPrimitive source, OsmPrimitive target) throws UserCancelException {
+    static List<Command> getTagConflictResolutionCommands(OsmPrimitive source, OsmPrimitive target) throws UserCancelException {
         Collection<OsmPrimitive> primitives = Arrays.asList(source, target);
         // launch a conflict resolution dialog, if necessary
@@ -480,5 +477,5 @@
      * @return null if there is no such node.
      */
-    protected static Node findNearestNode(Node node, Collection<Node> nodes) {
+    static Node findNearestNode(Node node, Collection<Node> nodes) {
         if (nodes.contains(node))
             return node;
