forked from diffplug/spotless
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJarState.java
More file actions
180 lines (155 loc) · 6.45 KB
/
JarState.java
File metadata and controls
180 lines (155 loc) · 6.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
* Copyright 2016-2025 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.diffplug.spotless;
import java.io.File;
import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.net.URI;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Grabs a jar and its dependencies from maven,
* and makes it easy to access the collection in
* a classloader.
* <p>
* Serializes the full state of the jar, so it can
* catch changes in a SNAPSHOT version.
*/
public final class JarState implements Serializable {
private static final Logger logger = LoggerFactory.getLogger(JarState.class);
// Let the classloader be overridden for tools using different approaches to classloading
@Nullable
private static ClassLoader forcedClassLoader = null;
/** Overrides the classloader used by all JarStates. */
public static void setForcedClassLoader(@Nullable ClassLoader forcedClassLoader) {
if (!Objects.equals(JarState.forcedClassLoader, forcedClassLoader)) {
logger.info("Overriding the forced classloader for JarState from {} to {}", JarState.forcedClassLoader, forcedClassLoader);
}
JarState.forcedClassLoader = forcedClassLoader;
}
/** A lazily evaluated JarState, which becomes a set of files when serialized. */
public static class Promised implements Serializable {
private static final long serialVersionUID = 1L;
private final transient ThrowingEx.Supplier<JarState> supplier;
private FileSignature.Promised cached;
public Promised(ThrowingEx.Supplier<JarState> supplier) {
this.supplier = supplier;
}
public JarState get() {
try {
if (cached == null) {
JarState result = supplier.get();
cached = result.fileSignature.asPromise();
return result;
}
return new JarState(cached.get());
} catch (Exception e) {
throw ThrowingEx.asRuntime(e);
}
}
// override serialize output
private void writeObject(java.io.ObjectOutputStream out)
throws IOException {
get();
out.defaultWriteObject();
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
}
private void readObjectNoData() throws ObjectStreamException {
throw new UnsupportedOperationException();
}
}
public static Promised promise(ThrowingEx.Supplier<JarState> supplier) {
return new Promised(supplier);
}
private static final long serialVersionUID = 1L;
private final FileSignature fileSignature;
private JarState(FileSignature fileSignature) {
this.fileSignature = fileSignature;
}
/** Provisions the given maven coordinate and its transitive dependencies. */
public static JarState from(String mavenCoordinate, Provisioner provisioner) throws IOException {
return from(Collections.singletonList(mavenCoordinate), provisioner);
}
/** Provisions the given maven coordinates and their transitive dependencies. */
public static JarState from(Collection<String> mavenCoordinates, Provisioner provisioner) throws IOException {
return provisionWithTransitives(true, mavenCoordinates, provisioner);
}
/** Provisions the given maven coordinates without their transitive dependencies. */
public static JarState withoutTransitives(Collection<String> mavenCoordinates, Provisioner provisioner) throws IOException {
return provisionWithTransitives(false, mavenCoordinates, provisioner);
}
private static JarState provisionWithTransitives(boolean withTransitives, Collection<String> mavenCoordinates, Provisioner provisioner) throws IOException {
Objects.requireNonNull(mavenCoordinates, "mavenCoordinates");
Objects.requireNonNull(provisioner, "provisioner");
Set<File> jars = provisioner.provisionWithTransitives(withTransitives, mavenCoordinates);
if (jars.isEmpty()) {
throw new NoSuchElementException("Resolved to an empty result: " + mavenCoordinates.stream().collect(Collectors.joining(", ")));
}
FileSignature fileSignature = FileSignature.signAsSet(jars);
return new JarState(fileSignature);
}
/** Wraps the given collection of a files as a JarState, maintaining the order in the Collection. */
public static JarState preserveOrder(Collection<File> jars) throws IOException {
FileSignature fileSignature = FileSignature.signAsList(jars);
return new JarState(fileSignature);
}
URL[] jarUrls() {
return fileSignature.files().stream().map(File::toURI).map(ThrowingEx.wrap(URI::toURL)).toArray(URL[]::new);
}
/**
* Returns either a forcedClassloader ({@code JarState.setForcedClassLoader()}) or a classloader containing the only jars in this JarState.
* Look-up of classes in the {@code org.slf4j} package
* are not taken from the JarState, but instead redirected to the class loader of this class to enable
* passthrough logging.
* <br/>
* The lifetime of the underlying cacheloader is controlled by {@link SpotlessCache}.
*
* @see com.diffplug.spotless.JarState#setForcedClassLoader(ClassLoader)
*/
public ClassLoader getClassLoader() {
if (forcedClassLoader != null) {
return forcedClassLoader;
}
return SpotlessCache.instance().classloader(this);
}
/**
* Returns either a forcedClassloader ({@code JarState.setForcedClassLoader}) or a classloader containing the only jars in this JarState.
* Look-up of classes in the {@code org.slf4j} package
* are not taken from the JarState, but instead redirected to the class loader of this class to enable
* passthrough logging.
* <br/>
* The lifetime of the underlying cacheloader is controlled by {@link SpotlessCache}
*
* @see com.diffplug.spotless.JarState#setForcedClassLoader(ClassLoader)
*/
public ClassLoader getClassLoader(Serializable key) {
if (forcedClassLoader != null) {
return forcedClassLoader;
}
return SpotlessCache.instance().classloader(key, this);
}
}