Index: /trunk/ivy.xml
===================================================================
--- /trunk/ivy.xml	(revision 18876)
+++ /trunk/ivy.xml	(revision 18877)
@@ -30,4 +30,6 @@
         <dependency conf="api->default" org="org.apache.commons" name="commons-jcs3-core" rev="3.1"/>
         <dependency conf="api->default" org="org.apache.commons" name="commons-compress" rev="1.23.0"/>
+        <dependency conf="api->default" org="jakarta.annotation" name="jakarta.annotation-api" rev="2.1.1" />
+        <!-- jsr305 has some source files with non-free CC-BY-2.5 license. Remove after 2024-06-01 to give plugins time to migrate. See #23220 for details -->
         <dependency conf="api->default" org="com.google.code.findbugs" name="jsr305" rev="3.0.2"/>
         <dependency conf="api->default" org="org.tukaani" name="xz" rev="1.9"/>
@@ -47,4 +49,6 @@
         <dependency conf="sources->sources" org="org.apache.commons" name="commons-jcs3-core" rev="3.1"/>
         <dependency conf="sources->sources" org="org.apache.commons" name="commons-compress" rev="1.23.0"/>
+        <dependency conf="sources->sources" org="jakarta.annotation" name="jakarta.annotation-api" rev="2.1.1" />
+        <!-- jsr305 has some source files with non-free CC-BY-2.5 license. Remove after 2024-06-01 to give plugins time to migrate. See #23220 for details -->
         <dependency conf="sources->sources" org="com.google.code.findbugs" name="jsr305" rev="3.0.2"/>
         <dependency conf="sources->sources" org="org.tukaani" name="xz" rev="1.9"/>
Index: /trunk/src/org/openstreetmap/josm/data/notes/Note.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/notes/Note.java	(revision 18876)
+++ /trunk/src/org/openstreetmap/josm/data/notes/Note.java	(revision 18877)
@@ -12,5 +12,5 @@
 import org.openstreetmap.josm.data.coor.LatLon;
 
-import javax.annotation.Nullable;
+import jakarta.annotation.Nullable;
 
 /**
Index: /trunk/src/org/openstreetmap/josm/data/osm/pbf/Blob.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/pbf/Blob.java	(revision 18876)
+++ /trunk/src/org/openstreetmap/josm/data/osm/pbf/Blob.java	(revision 18877)
@@ -7,8 +7,8 @@
 import java.util.zip.InflaterInputStream;
 
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
+import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
 
-import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
 
 /**
Index: /trunk/src/org/openstreetmap/josm/data/osm/pbf/BlobHeader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/pbf/BlobHeader.java	(revision 18876)
+++ /trunk/src/org/openstreetmap/josm/data/osm/pbf/BlobHeader.java	(revision 18877)
@@ -2,6 +2,6 @@
 package org.openstreetmap.josm.data.osm.pbf;
 
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
 
 /**
Index: /trunk/src/org/openstreetmap/josm/data/osm/pbf/HeaderBlock.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/pbf/HeaderBlock.java	(revision 18876)
+++ /trunk/src/org/openstreetmap/josm/data/osm/pbf/HeaderBlock.java	(revision 18877)
@@ -2,8 +2,8 @@
 package org.openstreetmap.josm.data.osm.pbf;
 
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
+import org.openstreetmap.josm.data.osm.BBox;
 
-import org.openstreetmap.josm.data.osm.BBox;
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
 
 /**
Index: /trunk/src/org/openstreetmap/josm/data/osm/pbf/Info.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/pbf/Info.java	(revision 18876)
+++ /trunk/src/org/openstreetmap/josm/data/osm/pbf/Info.java	(revision 18877)
@@ -2,5 +2,5 @@
 package org.openstreetmap.josm.data.osm.pbf;
 
-import javax.annotation.Nullable;
+import jakarta.annotation.Nullable;
 
 /**
Index: /trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java	(revision 18876)
+++ /trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java	(revision 18877)
@@ -27,7 +27,4 @@
 import java.util.regex.PatternSyntaxException;
 import java.util.stream.Collectors;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 
 import org.openstreetmap.josm.data.Bounds;
@@ -59,4 +56,7 @@
 import org.openstreetmap.josm.tools.date.DateUtils;
 
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+
 /**
  * Implements a google-like search.
@@ -85,10 +85,29 @@
     private final boolean caseSensitive;
     private final boolean regexSearch;
-    private static final String rxErrorMsg = marktr("The regex \"{0}\" had a parse error at offset {1}, full error:\n\n{2}");
-    private static final String rxErrorMsgNoPos = marktr("The regex \"{0}\" had a parse error, full error:\n\n{1}");
+    private static final String REGEX_ERROR_MESSAGE = marktr("The regex \"{0}\" had a parse error at offset {1}, full error:\n\n{2}");
+    private static final String REGEX_ERROR_MESSAGE_NO_POSITION = marktr("The regex \"{0}\" had a parse error, full error:\n\n{1}");
+    private static final String RANGE_OF_NUMBERS_EXPECTED = marktr("Range of numbers expected");
     private final PushbackTokenizer tokenizer;
     private static final Map<String, SimpleMatchFactory> simpleMatchFactoryMap = new HashMap<>();
     private static final Map<String, UnaryMatchFactory> unaryMatchFactoryMap = new HashMap<>();
     private static final Map<String, BinaryMatchFactory> binaryMatchFactoryMap = new HashMap<>();
+
+    // Common literals
+    private static final String AREA_SIZE = "areasize";
+    private static final String CHANGESET = "changeset";
+    private static final String CLOSED = "closed";
+    private static final String DELETED = "deleted";
+    private static final String INCOMPLETE = "incomplete";
+    private static final String IN_DOWNLOADED_AREA = "indownloadedarea";
+    private static final String ALL_IN_DOWNLOADED_AREA = "all" + IN_DOWNLOADED_AREA;
+    private static final String MEMBERS = "members";
+    private static final String MODIFIED = "modified";
+    private static final String NODES = "nodes";
+    private static final String SELECTED = "selected";
+    private static final String TIMESTAMP = "timestamp";
+    private static final String UNTAGGED = "untagged";
+    private static final String VERSION = "version";
+    private static final String WAYS = "ways";
+    private static final String WAY_LENGTH = "waylength";
 
     static {
@@ -134,29 +153,29 @@
      */
     public static class CoreSimpleMatchFactory implements SimpleMatchFactory {
-        private final Collection<String> keywords = Arrays.asList("id", "version", "type", "user", "role",
-                "changeset", "nodes", "ways", "members", "tags", "areasize", "waylength", "modified", "deleted", "selected",
-                "incomplete", "untagged", "closed", "new", "indownloadedarea",
-                "allindownloadedarea", "timestamp", "nth", "nth%", "hasRole", "preset");
+        private final Collection<String> keywords = Arrays.asList("id", VERSION, "type", "user", "role",
+                CHANGESET, NODES, WAYS, MEMBERS, "tags", AREA_SIZE, WAY_LENGTH, MODIFIED, DELETED, SELECTED,
+                INCOMPLETE, UNTAGGED, CLOSED, "new", IN_DOWNLOADED_AREA,
+                ALL_IN_DOWNLOADED_AREA, TIMESTAMP, "nth", "nth%", "hasRole", "preset");
 
         @Override
         public Match get(String keyword, boolean caseSensitive, boolean regexSearch, PushbackTokenizer tokenizer) throws SearchParseError {
             switch(keyword) {
-            case "modified":
+            case MODIFIED:
                 return new Modified();
-            case "deleted":
+            case DELETED:
                 return new Deleted();
-            case "selected":
+            case SELECTED:
                 return new Selected();
-            case "incomplete":
+            case INCOMPLETE:
                 return new Incomplete();
-            case "untagged":
+            case UNTAGGED:
                 return new Untagged();
-            case "closed":
+            case CLOSED:
                 return new Closed();
             case "new":
                 return new New();
-            case "indownloadedarea":
+            case IN_DOWNLOADED_AREA:
                 return new InDataSourceArea(false);
-            case "allindownloadedarea":
+            case ALL_IN_DOWNLOADED_AREA:
                 return new InDataSourceArea(true);
             default:
@@ -174,5 +193,5 @@
                 case "id":
                     return new Id(tokenizer);
-                case "version":
+                case VERSION:
                     return new Version(tokenizer);
                 case "type":
@@ -184,17 +203,17 @@
                 case "role":
                     return new RoleMatch(tokenizer.readTextOrNumber());
-                case "changeset":
+                case CHANGESET:
                     return new ChangesetId(tokenizer);
-                case "nodes":
+                case NODES:
                     return new NodeCountRange(tokenizer);
-                case "ways":
+                case WAYS:
                     return new WayCountRange(tokenizer);
-                case "members":
+                case MEMBERS:
                     return new MemberCountRange(tokenizer);
                 case "tags":
                     return new TagCountRange(tokenizer);
-                case "areasize":
+                case AREA_SIZE:
                     return new AreaSize(tokenizer);
-                case "waylength":
+                case WAY_LENGTH:
                     return new WayLength(tokenizer);
                 case "nth":
@@ -204,5 +223,5 @@
                 case "hasRole":
                     return new HasRole(tokenizer);
-                case "timestamp":
+                case TIMESTAMP:
                     // add leading/trailing space in order to get expected split (e.g. "a--" => {"a", ""})
                     String rangeS = ' ' + tokenizer.readTextOrNumber() + ' ';
@@ -370,9 +389,9 @@
                 return Pattern.compile(regex, flags);
             } catch (PatternSyntaxException e) {
-                throw new SearchParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e);
+                throw new SearchParseError(tr(REGEX_ERROR_MESSAGE, e.getPattern(), e.getIndex(), e.getMessage()), e);
             } catch (IllegalArgumentException | StringIndexOutOfBoundsException e) {
                 // StringIndexOutOfBoundsException caught because of https://bugs.openjdk.java.net/browse/JI-9044959
                 // See #13870: To remove after we switch to a version of Java which resolves this bug
-                throw new SearchParseError(tr(rxErrorMsgNoPos, regex, e.getMessage()), e);
+                throw new SearchParseError(tr(REGEX_ERROR_MESSAGE_NO_POSITION, regex, e.getMessage()), e);
             }
         }
@@ -707,5 +726,5 @@
         @Override
         protected String getString() {
-            return "changeset";
+            return CHANGESET;
         }
     }
@@ -730,5 +749,5 @@
         @Override
         protected String getString() {
-            return "version";
+            return VERSION;
         }
     }
@@ -783,5 +802,5 @@
         private String getMv(Tagged osm) {
             String mv;
-            if ("timestamp".equals(key) && osm instanceof OsmPrimitive) {
+            if (TIMESTAMP.equals(key) && osm instanceof OsmPrimitive) {
                 mv = ((OsmPrimitive) osm).getInstant().toString();
             } else {
@@ -1429,5 +1448,5 @@
 
         NodeCountRange(PushbackTokenizer tokenizer) throws SearchParseError {
-            this(tokenizer.readRange(tr("Range of numbers expected")));
+            this(tokenizer.readRange(tr(RANGE_OF_NUMBERS_EXPECTED)));
         }
 
@@ -1445,5 +1464,5 @@
         @Override
         protected String getString() {
-            return "nodes";
+            return NODES;
         }
     }
@@ -1458,5 +1477,5 @@
 
         WayCountRange(PushbackTokenizer tokenizer) throws SearchParseError {
-            this(tokenizer.readRange(tr("Range of numbers expected")));
+            this(tokenizer.readRange(tr(RANGE_OF_NUMBERS_EXPECTED)));
         }
 
@@ -1487,5 +1506,5 @@
 
         MemberCountRange(PushbackTokenizer tokenizer) throws SearchParseError {
-            this(tokenizer.readRange(tr("Range of numbers expected")));
+            this(tokenizer.readRange(tr(RANGE_OF_NUMBERS_EXPECTED)));
         }
 
@@ -1502,5 +1521,5 @@
         @Override
         protected String getString() {
-            return "members";
+            return MEMBERS;
         }
     }
@@ -1515,5 +1534,5 @@
 
         TagCountRange(PushbackTokenizer tokenizer) throws SearchParseError {
-            this(tokenizer.readRange(tr("Range of numbers expected")));
+            this(tokenizer.readRange(tr(RANGE_OF_NUMBERS_EXPECTED)));
         }
 
@@ -1566,5 +1585,5 @@
         @Override
         protected String getString() {
-            return "timestamp";
+            return TIMESTAMP;
         }
     }
@@ -1627,5 +1646,5 @@
         @Override
         public String toString() {
-            return "modified";
+            return MODIFIED;
         }
     }
@@ -1642,5 +1661,5 @@
         @Override
         public String toString() {
-            return "deleted";
+            return DELETED;
         }
     }
@@ -1657,5 +1676,5 @@
         @Override
         public String toString() {
-            return "selected";
+            return SELECTED;
         }
     }
@@ -1674,5 +1693,5 @@
         @Override
         public String toString() {
-            return "incomplete";
+            return INCOMPLETE;
         }
     }
@@ -1691,5 +1710,5 @@
         @Override
         public String toString() {
-            return "untagged";
+            return UNTAGGED;
         }
     }
@@ -1706,5 +1725,5 @@
         @Override
         public String toString() {
-            return "closed";
+            return CLOSED;
         }
     }
@@ -1767,5 +1786,5 @@
 
         AreaSize(PushbackTokenizer tokenizer) throws SearchParseError {
-            this(tokenizer.readRange(tr("Range of numbers expected")));
+            this(tokenizer.readRange(tr(RANGE_OF_NUMBERS_EXPECTED)));
         }
 
@@ -1778,5 +1797,5 @@
         @Override
         protected String getString() {
-            return "areasize";
+            return AREA_SIZE;
         }
     }
@@ -1792,5 +1811,5 @@
 
         WayLength(PushbackTokenizer tokenizer) throws SearchParseError {
-            this(tokenizer.readRange(tr("Range of numbers expected")));
+            this(tokenizer.readRange(tr(RANGE_OF_NUMBERS_EXPECTED)));
         }
 
@@ -1805,5 +1824,5 @@
         @Override
         protected String getString() {
-            return "waylength";
+            return WAY_LENGTH;
         }
     }
@@ -1878,5 +1897,5 @@
         @Override
         public String toString() {
-            return all ? "allindownloadedarea" : "indownloadedarea";
+            return all ? ALL_IN_DOWNLOADED_AREA : IN_DOWNLOADED_AREA;
         }
     }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/viewers/projections/Equirectangular.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/viewers/projections/Equirectangular.java	(revision 18876)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/viewers/projections/Equirectangular.java	(revision 18877)
@@ -13,7 +13,4 @@
 import java.util.Set;
 
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
 import org.openstreetmap.josm.data.imagery.street_level.Projections;
 import org.openstreetmap.josm.gui.layer.geoimage.ImageDisplay;
@@ -21,4 +18,7 @@
 import org.openstreetmap.josm.gui.util.imagery.CameraPlane;
 import org.openstreetmap.josm.gui.util.imagery.Vector3D;
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
 
 /**
Index: /trunk/src/org/openstreetmap/josm/gui/util/imagery/CameraPlane.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/util/imagery/CameraPlane.java	(revision 18876)
+++ /trunk/src/org/openstreetmap/josm/gui/util/imagery/CameraPlane.java	(revision 18877)
@@ -11,5 +11,8 @@
 import java.awt.image.DataBufferInt;
 import java.util.stream.IntStream;
-import javax.annotation.Nullable;
+
+import org.openstreetmap.josm.tools.Logging;
+
+import jakarta.annotation.Nullable;
 
 /**
@@ -129,4 +132,5 @@
             res = rotate(vectors[x][y]);
         } catch (Exception e) {
+            Logging.trace(e);
             res = Vector3D.DEFAULT_VECTOR_3D;
         }
@@ -150,5 +154,5 @@
      * @param p Point within current plane.
      */
-    public void setRotation(final Point p) {
+    public synchronized void setRotation(final Point p) {
         setRotation(getVector3D(p));
     }
@@ -181,5 +185,5 @@
      * @param vec vector pointing new view position.
      */
-    public void setRotation(Vector3D vec) {
+    public synchronized void setRotation(Vector3D vec) {
         setRotation(vec.getPolarAngle(), vec.getAzimuthalAngle());
     }
Index: /trunk/src/org/openstreetmap/josm/io/OsmPbfReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/OsmPbfReader.java	(revision 18876)
+++ /trunk/src/org/openstreetmap/josm/io/OsmPbfReader.java	(revision 18877)
@@ -16,6 +16,6 @@
 import java.util.Set;
 
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
 
 import org.apache.commons.compress.utils.CountingInputStream;
Index: /trunk/src/org/openstreetmap/josm/io/auth/CredentialsAgent.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/auth/CredentialsAgent.java	(revision 18876)
+++ /trunk/src/org/openstreetmap/josm/io/auth/CredentialsAgent.java	(revision 18877)
@@ -6,8 +6,8 @@
 import java.net.PasswordAuthentication;
 
-import javax.annotation.Nullable;
-
 import org.openstreetmap.josm.data.oauth.IOAuthToken;
 import org.openstreetmap.josm.data.oauth.OAuthToken;
+
+import jakarta.annotation.Nullable;
 
 /**
