Skip to content

Commit 18d7e9a

Browse files
authored
Add Proxy/Proxies data model to MavenSettings (#7092)
* Add Proxy/Proxies data model to MavenSettings Add support for parsing proxy settings from Maven's settings.xml. This adds the Proxies and Proxy inner classes following the existing Servers/Server pattern, including merge, interpolation, and password decryption support. * Make Proxy.id non-nullable to fix silent data loss in Proxies.merge() Proxy.id was @nullable but used as a LinkedHashMap key in merge(), causing proxies with null ids to silently overwrite each other. This aligns with Server.id which is already non-nullable. * Address PR review: make Proxy.id and Proxy.port nullable per Maven defaults Per reviewer feedback, Proxy.id and Proxy.port now match Maven's settings schema where id defaults to "default" and port defaults to 8080. Both are now @nullable to accurately represent when values are omitted from XML. Proxies.merge() is updated to handle null ids by assigning synthetic keys, preventing silent data loss when multiple proxies omit the id element.
1 parent 5c4736e commit 18d7e9a

File tree

2 files changed

+127
-3
lines changed

2 files changed

+127
-3
lines changed

rewrite-maven/src/main/java/org/openrewrite/maven/MavenSettings.java

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,25 @@ public class MavenSettings {
7373
@With
7474
Servers servers;
7575

76-
@JsonCreator
76+
@Nullable
77+
Proxies proxies;
78+
7779
public MavenSettings(@Nullable String localRepository, @Nullable Profiles profiles,
7880
@Nullable ActiveProfiles activeProfiles, @Nullable Mirrors mirrors,
7981
@Nullable Servers servers) {
82+
this(localRepository, profiles, activeProfiles, mirrors, servers, null);
83+
}
84+
85+
@JsonCreator
86+
public MavenSettings(@Nullable String localRepository, @Nullable Profiles profiles,
87+
@Nullable ActiveProfiles activeProfiles, @Nullable Mirrors mirrors,
88+
@Nullable Servers servers, @Nullable Proxies proxies) {
8089
this.localRepository = localRepository;
8190
this.profiles = profiles;
8291
this.activeProfiles = activeProfiles;
8392
this.mirrors = mirrors;
8493
this.servers = servers;
94+
this.proxies = proxies;
8595
}
8696

8797
public static @Nullable MavenSettings parse(Parser.Input source, ExecutionContext ctx) {
@@ -148,6 +158,12 @@ void maybeDecryptPasswords(ExecutionContext ctx) {
148158
return password == null ? server : server.withPassword(password);
149159
});
150160
}
161+
if (proxies != null) {
162+
proxies.proxies = ListUtils.map(proxies.proxies, proxy -> {
163+
String password = security.decrypt(proxy.getPassword(), decryptedMasterPassword);
164+
return password == null ? proxy : proxy.withPassword(password);
165+
});
166+
}
151167
}
152168
}
153169

@@ -192,7 +208,8 @@ public MavenSettings merge(@Nullable MavenSettings installSettings) {
192208
profiles == null ? installSettings.profiles : profiles.merge(installSettings.profiles),
193209
activeProfiles == null ? installSettings.activeProfiles : activeProfiles.merge(installSettings.activeProfiles),
194210
mirrors == null ? installSettings.mirrors : mirrors.merge(installSettings.mirrors),
195-
servers == null ? installSettings.servers : servers.merge(installSettings.servers)
211+
servers == null ? installSettings.servers : servers.merge(installSettings.servers),
212+
proxies == null ? installSettings.proxies : proxies.merge(installSettings.proxies)
196213
);
197214
}
198215

@@ -254,7 +271,8 @@ public MavenSettings interpolate(MavenSettings mavenSettings) {
254271
mavenSettings.profiles,
255272
interpolate(mavenSettings.activeProfiles),
256273
interpolate(mavenSettings.mirrors),
257-
interpolate(mavenSettings.servers));
274+
interpolate(mavenSettings.servers),
275+
interpolate(mavenSettings.proxies));
258276
}
259277

260278
private @Nullable ActiveProfiles interpolate(@Nullable ActiveProfiles activeProfiles) {
@@ -295,6 +313,17 @@ private Server interpolate(Server server) {
295313
interpolate(server.configuration));
296314
}
297315

316+
private @Nullable Proxies interpolate(@Nullable Proxies proxies) {
317+
if (proxies == null) return null;
318+
return new Proxies(ListUtils.map(proxies.getProxies(), this::interpolate));
319+
}
320+
321+
private Proxy interpolate(Proxy proxy) {
322+
return new Proxy(interpolate(proxy.id), proxy.active, interpolate(proxy.protocol),
323+
interpolate(proxy.host), proxy.port, interpolate(proxy.username),
324+
interpolate(proxy.password), interpolate(proxy.nonProxyHosts));
325+
}
326+
298327
private @Nullable String interpolate(@Nullable String s) {
299328
return s == null ? null : propertyPlaceholders.replacePlaceholders(s, propertyResolver);
300329
}
@@ -446,6 +475,64 @@ public static class Server {
446475
ServerConfiguration configuration;
447476
}
448477

478+
@FieldDefaults(level = AccessLevel.PRIVATE)
479+
@Getter
480+
@Setter
481+
@AllArgsConstructor
482+
@NoArgsConstructor
483+
public static class Proxies {
484+
@JacksonXmlProperty(localName = "proxy")
485+
@JacksonXmlElementWrapper(useWrapping = false)
486+
List<Proxy> proxies = emptyList();
487+
488+
public Proxies merge(@Nullable Proxies proxies) {
489+
final Map<String, Proxy> merged = new LinkedHashMap<>();
490+
int nullIndex = 0;
491+
for (Proxy proxy : this.proxies) {
492+
String key = proxy.id != null ? proxy.id : "__null_" + nullIndex++;
493+
merged.put(key, proxy);
494+
}
495+
if (proxies != null) {
496+
for (Proxy proxy : proxies.getProxies()) {
497+
if (proxy.getId() != null) {
498+
merged.putIfAbsent(proxy.getId(), proxy);
499+
} else {
500+
merged.put("__null_" + nullIndex++, proxy);
501+
}
502+
}
503+
}
504+
return new Proxies(new ArrayList<>(merged.values()));
505+
}
506+
}
507+
508+
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
509+
@Data
510+
@With
511+
public static class Proxy {
512+
@Nullable
513+
String id;
514+
515+
@Nullable
516+
Boolean active;
517+
518+
@Nullable
519+
String protocol;
520+
521+
String host;
522+
523+
@Nullable
524+
Integer port;
525+
526+
@Nullable
527+
String username;
528+
529+
@Nullable
530+
String password;
531+
532+
@Nullable
533+
String nonProxyHosts;
534+
}
535+
449536
@EqualsAndHashCode
450537
@FieldDefaults(level = AccessLevel.PRIVATE)
451538
@ToString

rewrite-maven/src/test/java/org/openrewrite/maven/MavenSettingsTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,4 +1011,41 @@ private void createSettingsSecurityFile() throws IOException {
10111011
</settingsSecurity>
10121012
""".formatted(MASTER_PASS_ENCRYPTED));
10131013
}
1014+
1015+
@Test
1016+
@Issue("https://github.com/openrewrite/rewrite-maven-plugin/issues/543")
1017+
void parseProxies() {
1018+
MavenSettings settings = MavenSettings.parse(Parser.Input.fromString(Path.of("settings.xml"),
1019+
//language=xml
1020+
"""
1021+
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0">
1022+
<proxies>
1023+
<proxy>
1024+
<id>my-proxy</id>
1025+
<active>true</active>
1026+
<protocol>https</protocol>
1027+
<host>proxy.example.com</host>
1028+
<port>8080</port>
1029+
<username>proxyuser</username>
1030+
<password>proxypass</password>
1031+
<nonProxyHosts>localhost|*.example.com</nonProxyHosts>
1032+
</proxy>
1033+
</proxies>
1034+
</settings>
1035+
"""), ctx);
1036+
1037+
assertThat(settings).isNotNull();
1038+
assertThat(settings.getProxies()).isNotNull();
1039+
assertThat(settings.getProxies().getProxies()).hasSize(1);
1040+
1041+
MavenSettings.Proxy proxy = settings.getProxies().getProxies().get(0);
1042+
assertThat(proxy.getId()).isEqualTo("my-proxy");
1043+
assertThat(proxy.getActive()).isTrue();
1044+
assertThat(proxy.getProtocol()).isEqualTo("https");
1045+
assertThat(proxy.getHost()).isEqualTo("proxy.example.com");
1046+
assertThat(proxy.getPort()).isEqualTo(8080);
1047+
assertThat(proxy.getUsername()).isEqualTo("proxyuser");
1048+
assertThat(proxy.getPassword()).isEqualTo("proxypass");
1049+
assertThat(proxy.getNonProxyHosts()).isEqualTo("localhost|*.example.com");
1050+
}
10141051
}

0 commit comments

Comments
 (0)