Skip to content

Commit fe5f911

Browse files
committed
fully support package private
will now generate separate HttpComponents for package-private client interfaces
1 parent b5fe961 commit fe5f911

File tree

9 files changed

+184
-71
lines changed

9 files changed

+184
-71
lines changed

http-generator-client/src/main/java/io/avaje/http/generator/client/ClientProcessor.java

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package io.avaje.http.generator.client;
22

3+
import static io.avaje.http.generator.core.ProcessingContext.createMetaInfWriter;
34
import static io.avaje.http.generator.core.ProcessingContext.logError;
45
import static io.avaje.http.generator.core.ProcessingContext.platform;
56
import static io.avaje.http.generator.core.ProcessingContext.setPlatform;
67
import static io.avaje.http.generator.core.ProcessingContext.typeElement;
78

89
import java.io.IOException;
10+
import java.util.HashMap;
11+
import java.util.Map;
912
import java.util.Objects;
1013
import java.util.Set;
1114

@@ -15,10 +18,13 @@
1518
import javax.annotation.processing.SupportedAnnotationTypes;
1619
import javax.lang.model.SourceVersion;
1720
import javax.lang.model.element.Element;
21+
import javax.lang.model.element.Modifier;
1822
import javax.lang.model.element.TypeElement;
23+
import javax.tools.FileObject;
1924

2025
import io.avaje.http.generator.core.APContext;
2126
import io.avaje.http.generator.core.ClientPrism;
27+
import io.avaje.http.generator.core.Constants;
2228
import io.avaje.http.generator.core.ControllerReader;
2329
import io.avaje.http.generator.core.ImportPrism;
2430
import io.avaje.http.generator.core.ProcessingContext;
@@ -30,6 +36,8 @@ public class ClientProcessor extends AbstractProcessor {
3036

3137
private final ComponentMetaData metaData = new ComponentMetaData();
3238

39+
private final Map<String, ComponentMetaData> privateMetaData = new HashMap<>();
40+
3341
private boolean useJsonB;
3442

3543
private SimpleComponentWriter componentWriter;
@@ -79,7 +87,7 @@ private void readModule() {
7987
return;
8088
}
8189
readModuleInfo = true;
82-
new ComponentReader(metaData).read();
90+
new ComponentReader(metaData, privateMetaData).read();
8391
}
8492

8593
private void writeForImported(Element importedElement) {
@@ -94,39 +102,75 @@ private void writeClient(Element controller) {
94102
final ControllerReader reader = new ControllerReader((TypeElement) controller);
95103
reader.read(false);
96104
try {
97-
metaData.add(writeClientAdapter(reader));
105+
106+
var packagePrivate =
107+
!controller.getModifiers().contains(Modifier.PUBLIC)
108+
&& ClientPrism.isPresent(controller);
109+
if (packagePrivate) {
110+
var packageName =
111+
APContext.elements().getPackageOf(controller).getQualifiedName().toString();
112+
var meta = privateMetaData.computeIfAbsent(packageName, k -> new ComponentMetaData());
113+
meta.add(writeClientAdapter(reader, true));
114+
} else {
115+
metaData.add(writeClientAdapter(reader, false));
116+
}
117+
98118
} catch (final Exception e) {
99119
logError(reader.beanType(), "Failed to write client class " + e);
100120
}
101121
}
102122
}
103123

104-
protected String writeClientAdapter(ControllerReader reader) throws IOException {
124+
protected String writeClientAdapter(ControllerReader reader, boolean packagePrivate) throws IOException {
105125
var suffix = ClientSuffix.fromInterface(reader.beanType().getQualifiedName().toString());
106-
return new ClientWriter(reader, suffix, useJsonB).write();
107-
}
108-
109-
private void initialiseComponent() {
110-
metaData.initialiseFullName();
111-
if (!metaData.all().isEmpty()) {
112-
ProcessingContext.addClientComponent(metaData.fullName());
113-
ProcessingContext.validateModule();
114-
}
115-
try {
116-
componentWriter.init();
117-
} catch (final IOException e) {
118-
logError("Error creating writer for JsonbComponent", e);
119-
}
126+
return new ClientWriter(reader, suffix, useJsonB, packagePrivate).write();
120127
}
121128

122129
private void writeComponent(boolean processingOver) {
123-
initialiseComponent();
124130
if (processingOver) {
131+
125132
try {
126-
componentWriter.write();
133+
134+
135+
if (!metaData.all().isEmpty()) {
136+
ProcessingContext.addClientComponent(metaData.fullName());
137+
138+
componentWriter.init();
139+
componentWriter.write();
140+
}
141+
142+
for (var meta : privateMetaData.values()) {
143+
ProcessingContext.addClientComponent(meta.fullName());
144+
145+
var writer = new SimpleComponentWriter(meta);
146+
writer.init();
147+
writer.write();
148+
}
149+
writeMetaInf();
150+
ProcessingContext.validateModule();
127151
} catch (final IOException e) {
128152
logError("Error writing component", e);
129153
}
130154
}
131155
}
156+
157+
void writeMetaInf() throws IOException {
158+
final FileObject fileObject = createMetaInfWriter(Constants.META_INF_COMPONENT);
159+
if (fileObject != null) {
160+
try (var fileWriter = fileObject.openWriter()) {
161+
162+
if (!metaData.all().isEmpty()) {
163+
164+
fileWriter.write(metaData.fullName());
165+
fileWriter.write("\n");
166+
}
167+
168+
for (var meta : privateMetaData.values()) {
169+
170+
fileWriter.write(meta.fullName());
171+
fileWriter.write("\n");
172+
}
173+
}
174+
}
175+
}
132176
}

http-generator-client/src/main/java/io/avaje/http/generator/client/ClientWriter.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.avaje.http.generator.client;
22

3-
import io.avaje.http.generator.core.APContext;
43
import io.avaje.http.generator.core.BaseControllerWriter;
54
import io.avaje.http.generator.core.ClientPrism;
65
import io.avaje.http.generator.core.ControllerReader;
@@ -28,9 +27,12 @@ final class ClientWriter extends BaseControllerWriter {
2827
private final Set<String> propertyConstants = new HashSet<>();
2928
private final String suffix;
3029

31-
ClientWriter(ControllerReader reader, String suffix, boolean useJsonB) throws IOException {
30+
private final boolean packagePrivate;
31+
32+
ClientWriter(ControllerReader reader, String suffix, boolean useJsonB, boolean packagePrivate) throws IOException {
3233
super(reader, suffix);
3334
this.suffix = suffix;
35+
this.packagePrivate = packagePrivate;
3436
reader.addImportType(HTTP_CLIENT);
3537
this.useJsonb = useJsonB;
3638
readMethods();
@@ -79,12 +81,12 @@ private void writeMethods() {
7981
private void writeClassStart() {
8082
writer.append(AT_GENERATED).eol();
8183
AnnotationUtil.writeAnnotations(writer, reader.beanType());
82-
83-
writer.append("public final class %s%s implements %s, AutoCloseable {", shortName, suffix, shortName).eol().eol();
84+
var access = packagePrivate ? "" : "public ";
85+
writer.append("%sfinal class %s%s implements %s, AutoCloseable {", access, shortName, suffix, shortName).eol().eol();
8486

8587
writer.append(" private final HttpClient client;").eol().eol();
8688

87-
writer.append(" public %s%s(HttpClient client) {", shortName, suffix).eol();
89+
writer.append(" %s%s%s(HttpClient client) {", access, shortName, suffix).eol();
8890
writer.append(" this.client = client;").eol();
8991
writer.append(" }").eol().eol();
9092
}

http-generator-client/src/main/java/io/avaje/http/generator/client/ComponentMetaData.java

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,14 @@
44

55
final class ComponentMetaData {
66

7-
private final List<String> generatedClients = new ArrayList<>();
7+
private final Set<String> generatedClients = new HashSet<>();
88
private String fullName;
99

1010
@Override
1111
public String toString() {
1212
return generatedClients.toString();
1313
}
1414

15-
/** Ensure the component name has been initialised. */
16-
void initialiseFullName() {
17-
fullName();
18-
}
19-
2015
void add(String type) {
2116
generatedClients.add(type);
2217
}
@@ -28,13 +23,13 @@ void setFullName(String fullName) {
2823
String fullName() {
2924
if (fullName == null) {
3025
String topPackage = TopPackage.of(generatedClients);
31-
fullName = topPackage + ".GeneratedHttpComponent";
26+
fullName = topPackage + "." + name(topPackage) + "HttpComponent";
3227
}
3328
return fullName;
3429
}
3530

3631
List<String> all() {
37-
return generatedClients;
32+
return new ArrayList<>(generatedClients);
3833
}
3934

4035
/** Return the package imports for the JsonAdapters and related types. */
@@ -46,4 +41,37 @@ Collection<String> allImports() {
4641

4742
return packageImports;
4843
}
44+
45+
46+
static String name(String name) {
47+
if (name == null) {
48+
return null;
49+
}
50+
final int pos = name.lastIndexOf('.');
51+
if (pos > -1) {
52+
name = name.substring(pos + 1);
53+
}
54+
return camelCase(name).replaceFirst("Httpclient", "Generated");
55+
}
56+
57+
private static String camelCase(String name) {
58+
StringBuilder sb = new StringBuilder(name.length());
59+
boolean upper = true;
60+
for (char aChar : name.toCharArray()) {
61+
if (Character.isLetterOrDigit(aChar)) {
62+
if (upper) {
63+
aChar = Character.toUpperCase(aChar);
64+
upper = false;
65+
}
66+
sb.append(aChar);
67+
} else if (toUpperOn(aChar)) {
68+
upper = true;
69+
}
70+
}
71+
return sb.toString();
72+
}
73+
74+
private static boolean toUpperOn(char aChar) {
75+
return aChar == ' ' || aChar == '-' || aChar == '_';
76+
}
4977
}

http-generator-client/src/main/java/io/avaje/http/generator/client/ComponentReader.java

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package io.avaje.http.generator.client;
2+
23
import static io.avaje.http.generator.core.ProcessingContext.filer;
34
import static io.avaje.http.generator.core.ProcessingContext.logDebug;
45
import static io.avaje.http.generator.core.ProcessingContext.logWarn;
56
import static io.avaje.http.generator.core.ProcessingContext.typeElement;
7+
import static java.util.stream.Collectors.toList;
68

79
import java.io.FileNotFoundException;
810
import java.io.LineNumberReader;
@@ -11,56 +13,64 @@
1113
import java.util.ArrayList;
1214
import java.util.Collections;
1315
import java.util.List;
16+
import java.util.Map;
1417

1518
import javax.annotation.processing.FilerException;
16-
import javax.lang.model.element.AnnotationMirror;
19+
import javax.lang.model.element.Modifier;
1720
import javax.lang.model.element.TypeElement;
18-
import javax.lang.model.type.TypeMirror;
1921
import javax.tools.FileObject;
2022
import javax.tools.StandardLocation;
2123

24+
import io.avaje.http.generator.core.APContext;
2225
import io.avaje.http.generator.core.Constants;
2326
import io.avaje.prism.GeneratePrism;
2427

2528
@GeneratePrism(io.avaje.http.api.spi.MetaData.class)
2629
final class ComponentReader {
2730

2831
private final ComponentMetaData componentMetaData;
32+
private final Map<String, ComponentMetaData> privateMetaData;
2933

30-
ComponentReader(ComponentMetaData metaData) {
34+
ComponentReader(ComponentMetaData metaData, Map<String, ComponentMetaData> privateMetaData) {
3135
this.componentMetaData = metaData;
36+
this.privateMetaData = privateMetaData;
3237
}
3338

3439
void read() {
35-
final String componentFullName = loadMetaInfServices();
36-
if (componentFullName != null) {
37-
final TypeElement moduleType = typeElement(componentFullName);
40+
41+
for (String fqn : loadMetaInf()) {
42+
43+
final TypeElement moduleType = typeElement(fqn);
3844
if (moduleType != null) {
39-
componentMetaData.setFullName(componentFullName);
40-
readMetaData(moduleType);
41-
}
42-
}
43-
}
45+
var adapters =
46+
MetaDataPrism.getInstanceOn(moduleType).value().stream()
47+
.map(APContext::asTypeElement)
48+
.collect(toList());
4449

45-
/** Read the existing JsonAdapters from the MetaData annotation of the generated component. */
46-
private void readMetaData(TypeElement moduleType) {
47-
for (final AnnotationMirror annotationMirror : moduleType.getAnnotationMirrors()) {
48-
MetaDataPrism.getOptional(annotationMirror).map(MetaDataPrism::value).stream()
49-
.flatMap(List::stream)
50-
.map(TypeMirror::toString)
51-
.forEach(componentMetaData::add);
52-
}
53-
}
50+
if (adapters.get(0).getModifiers().contains(Modifier.PUBLIC)) {
51+
componentMetaData.setFullName(fqn);
52+
adapters.stream()
53+
.map(TypeElement::getQualifiedName)
54+
.map(Object::toString)
55+
.forEach(componentMetaData::add);
5456

55-
private String loadMetaInfServices() {
56-
final List<String> lines = loadMetaInf();
57-
return lines.isEmpty() ? null : lines.get(0);
57+
} else {
58+
var packageName =
59+
APContext.elements().getPackageOf(moduleType).getQualifiedName().toString();
60+
var meta = privateMetaData.computeIfAbsent(packageName, k -> new ComponentMetaData());
61+
adapters.stream()
62+
.map(TypeElement::getQualifiedName)
63+
.map(Object::toString)
64+
.forEach(meta::add);
65+
}
66+
}
67+
}
5868
}
5969

6070
private List<String> loadMetaInf() {
6171
try {
62-
final FileObject fileObject = filer()
63-
.getResource(StandardLocation.CLASS_OUTPUT, "", Constants.META_INF_COMPONENT);
72+
final FileObject fileObject =
73+
filer().getResource(StandardLocation.CLASS_OUTPUT, "", Constants.META_INF_COMPONENT);
6474

6575
if (fileObject != null) {
6676
final List<String> lines = new ArrayList<>();

http-generator-client/src/main/java/io/avaje/http/generator/client/SimpleComponentWriter.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,6 @@ void write() throws IOException {
4646
writeRegister();
4747
writeClassEnd();
4848
writer.close();
49-
writeMetaInf();
50-
}
51-
52-
void writeMetaInf() throws IOException {
53-
final FileObject fileObject = createMetaInfWriter(Constants.META_INF_COMPONENT);
54-
if (fileObject != null) {
55-
try (var fileWriter = fileObject.openWriter()) {
56-
fileWriter.write(fullName);
57-
}
58-
}
5949
}
6050

6151
private void writeRegister() {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.avaje.http.generator.client.clients;
2+
3+
import io.avaje.http.api.Client;
4+
import io.avaje.http.api.Get;
5+
import io.avaje.http.api.Header;
6+
7+
@Client
8+
interface PrivateClient {
9+
10+
@Get("/private")
11+
String apiCall(@Header("Accept") String accept);
12+
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.avaje.http.generator.client.clients;
2+
3+
import io.avaje.http.api.Client;
4+
import io.avaje.http.api.Get;
5+
import io.avaje.http.api.Header;
6+
7+
@Client
8+
public interface PrivateClient2 {
9+
10+
@Get("/private")
11+
String apiCall(@Header("Accept") String accept);
12+
13+
}

0 commit comments

Comments
 (0)