Skip to content

Commit cdfdbb4

Browse files
committed
#330: Fixed issue with the duplicate declared cli options being recorded. Also fixed broken CLI support with the latest performance upgrade. Also greatly improved the error feedback for failed CLI commands
1 parent 2fafb1e commit cdfdbb4

File tree

7 files changed

+34
-28
lines changed

7 files changed

+34
-28
lines changed

modules/batch-module/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
<dependency>
3535
<groupId>org.simplejavamail</groupId>
3636
<artifactId>smtp-connection-pool</artifactId>
37-
<version>1.1.1</version>
37+
<version>1.1.2</version>
3838
</dependency>
3939
</dependencies>
4040
</project>

modules/cli-module/src/main/java/org/simplejavamail/internal/clisupport/BuilderApiToPicocliCommandsMapper.java

+5-6
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@
3737
import java.security.cert.X509Certificate;
3838
import java.util.ArrayList;
3939
import java.util.Arrays;
40-
import java.util.Collections;
4140
import java.util.Date;
4241
import java.util.HashMap;
4342
import java.util.HashSet;
4443
import java.util.List;
4544
import java.util.Map;
4645
import java.util.Set;
46+
import java.util.TreeSet;
4747
import java.util.UUID;
4848
import java.util.regex.Matcher;
4949
import java.util.regex.Pattern;
@@ -102,16 +102,15 @@ private BuilderApiToPicocliCommandsMapper() {
102102

103103
@NotNull
104104
static List<CliDeclaredOptionSpec> generateOptionsFromBuilderApi(@SuppressWarnings("SameParameterValue") Class<?>[] relevantBuilderRootApi) {
105-
final List<CliDeclaredOptionSpec> cliOptions = new ArrayList<>();
105+
final Set<CliDeclaredOptionSpec> cliOptions = new TreeSet<>();
106106
final Set<Class<?>> processedApiNodes = new HashSet<>();
107107
for (Class<?> apiRoot : relevantBuilderRootApi) {
108108
generateOptionsFromBuilderApiChain(apiRoot, processedApiNodes, cliOptions);
109109
}
110-
Collections.sort(cliOptions);
111-
return cliOptions;
110+
return new ArrayList<>(cliOptions);
112111
}
113112

114-
private static void generateOptionsFromBuilderApiChain(Class<?> apiNode, Set<Class<?>> processedApiNodes, List<CliDeclaredOptionSpec> cliOptionsFoundSoFar) {
113+
private static void generateOptionsFromBuilderApiChain(Class<?> apiNode, Set<Class<?>> processedApiNodes, Set<CliDeclaredOptionSpec> cliOptionsFoundSoFar) {
115114
Class<?> apiNodeChainClass = apiNode;
116115
while (apiNodeChainClass != null && apiNodeChainClass.getPackage().getName().contains("org.simplejavamail")) {
117116
for (Class<?> apiInterface : apiNodeChainClass.getInterfaces()) {
@@ -126,7 +125,7 @@ private static void generateOptionsFromBuilderApiChain(Class<?> apiNode, Set<Cla
126125
* Produces all the --option Picocli-based params for specific API class. <br>
127126
* Recursive for returned API class (since builders can return different builders.
128127
*/
129-
private static void generateOptionsFromBuilderApi(Class<?> apiNode, Set<Class<?>> processedApiNodes, List<CliDeclaredOptionSpec> cliOptionsFoundSoFar) {
128+
private static void generateOptionsFromBuilderApi(Class<?> apiNode, Set<Class<?>> processedApiNodes, Set<CliDeclaredOptionSpec> cliOptionsFoundSoFar) {
130129
if (processedApiNodes.contains(apiNode)) {
131130
return;
132131
}

modules/cli-module/src/main/java/org/simplejavamail/internal/clisupport/CliCommandLineConsumer.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ static CliReceivedCommand consumeCommandLineInput(ParseResult providedCommand, @
5050
final int mandatoryParameters = MiscUtil.countMandatoryParameters(sourceMethod);
5151
final List<String> providedStringValues = cliOption.getValue().getValue();
5252
assumeTrue(providedStringValues.size() >= mandatoryParameters,
53-
format("provided %s arguments, but need at least %s", providedStringValues.size(), mandatoryParameters));
53+
format("provided %s arguments for '%s', but need at least %s", providedStringValues.size(), cliOption.getKey(), mandatoryParameters));
5454
assumeTrue(providedStringValues.size() <= sourceMethod.getParameterTypes().length,
55-
format("provided %s arguments, but need at most %s", providedStringValues.size(), sourceMethod.getParameterTypes().length));
55+
format("provided %s arguments for '%s', but need at most %s", providedStringValues.size(), cliOption.getKey(), sourceMethod.getParameterTypes().length));
5656
receivedOptions.add(new CliReceivedOptionData(cliOption.getKey(), convertProvidedOptionValues(providedStringValues, sourceMethod)));
5757
LOGGER.debug("\tconverted option values: {}", getLast(receivedOptions).getProvidedOptionValues());
5858
}

modules/cli-module/src/main/java/org/simplejavamail/internal/clisupport/CliCommandLineConsumerResultHandler.java

+22-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.simplejavamail.internal.clisupport;
22

3+
import org.jetbrains.annotations.NotNull;
34
import org.simplejavamail.api.email.EmailPopulatingBuilder;
45
import org.simplejavamail.api.internal.clisupport.model.CliBuilderApiType;
56
import org.simplejavamail.api.internal.clisupport.model.CliReceivedCommand;
@@ -10,8 +11,10 @@
1011
import org.slf4j.Logger;
1112

1213
import java.lang.reflect.InvocationTargetException;
14+
import java.lang.reflect.Method;
1315
import java.util.List;
1416

17+
import static java.lang.String.format;
1518
import static org.slf4j.LoggerFactory.getLogger;
1619

1720
class CliCommandLineConsumerResultHandler {
@@ -58,14 +61,30 @@ private static <T> T invokeBuilderApi(List<CliReceivedOptionData> cliReceivedOpt
5861
if (option.determineTargetBuilderApi() == builderApiType) {
5962
try {
6063
LOGGER.debug("\t\t.{}({})", option.getDeclaredOptionSpec().getSourceMethod().getName(), option.getProvidedOptionValues());
61-
currentBuilder = option.getDeclaredOptionSpec().getSourceMethod().invoke(currentBuilder, option.getProvidedOptionValues().toArray());
64+
65+
Method sourceMethod = determineTrueSourceMethod(option.getDeclaredOptionSpec().getSourceMethod());
66+
67+
currentBuilder = sourceMethod.invoke(currentBuilder, option.getProvidedOptionValues().toArray());
6268
} catch (IllegalArgumentException e) {
63-
throw new CliExecutionException(CliExecutionException.WRONG_CURRENT_BUILDER, e);
69+
throw new CliExecutionException(formatCliInvocationError(CliExecutionException.WRONG_CURRENT_BUILDER, option), e);
6470
} catch (IllegalAccessException | InvocationTargetException e) {
65-
throw new CliExecutionException(CliExecutionException.ERROR_INVOKING_BUILDER_API, e);
71+
throw new CliExecutionException(formatCliInvocationError(CliExecutionException.ERROR_INVOKING_BUILDER_API, option), e);
72+
} catch (NoSuchMethodException e) {
73+
throw new CliExecutionException("This should never happen", e);
6674
}
6775
}
6876
}
6977
return (T) currentBuilder;
7078
}
79+
80+
@NotNull
81+
// yeah, so after deserializing a java.lang.Method, it's actually a fake, so let's find it's real counter version
82+
private static Method determineTrueSourceMethod(@NotNull Method sourceMethod)
83+
throws NoSuchMethodException {
84+
return sourceMethod.getDeclaringClass().getDeclaredMethod(sourceMethod.getName(), sourceMethod.getParameterTypes());
85+
}
86+
87+
private static String formatCliInvocationError(final String exceptionTemplate, final CliReceivedOptionData option) {
88+
return format(exceptionTemplate, option.getProvidedOptionValues(), option.getDeclaredOptionSpec().getName());
89+
}
7190
}

modules/cli-module/src/main/java/org/simplejavamail/internal/clisupport/CliExecutionException.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
@SuppressWarnings("serial")
99
class CliExecutionException extends MailException {
1010

11-
static final String WRONG_CURRENT_BUILDER = "Wrong argument for the current builder API. Make sure you start with one of the following options:\n" +
11+
static final String WRONG_CURRENT_BUILDER = "Wrong argument(s) '%s' for '%s'.\nAlso, make sure you start with one of the following options:\n" +
1212
"\t\t--email:startingBlank\n" +
1313
"\t\t--email:copying message(=FILE)\n" +
1414
"\t\t--email:forwarding message(=FILE)\n" +
@@ -17,7 +17,7 @@ class CliExecutionException extends MailException {
1717
"\t\t--email:replyingToSenderWithDefaultQuoteMarkup message(=FILE)\n" +
1818
"\t\t--email:replyingToAll message(=FILE) customQuotingTemplate(=TEXT)\n" +
1919
"\t\t--email:replyingToAllWithDefaultQuoteMarkup message(=FILE)";
20-
static final String ERROR_INVOKING_BUILDER_API = "Got error while invoking Builder API";
20+
static final String ERROR_INVOKING_BUILDER_API = "Got error while invoking Builder API with argument(s) '%s' for '%s'";
2121

2222
CliExecutionException(String message, Exception cause) {
2323
super(message, cause);

modules/cli-module/src/main/java/org/simplejavamail/internal/clisupport/CliSupport.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ private static List<CliDeclaredOptionSpec> produceCliDeclaredOptionSpec() {
3737
try {
3838
if (!CLI_DATAFILE.exists()) {
3939
LOGGER.info("Initial cli.data not found, writing to (one time action): {}", CLI_DATAFILE);
40-
List<CliDeclaredOptionSpec> serializable = generateOptionsFromBuilderApi(RELEVANT_BUILDER_ROOT_API);
41-
MiscUtil.writeFileBytes(CLI_DATAFILE, SerializationUtil.serialize(serializable));
40+
List<CliDeclaredOptionSpec> declaredOptions = generateOptionsFromBuilderApi(RELEVANT_BUILDER_ROOT_API);
41+
MiscUtil.writeFileBytes(CLI_DATAFILE, SerializationUtil.serialize(declaredOptions));
4242
}
4343
return SerializationUtil.deserialize(MiscUtil.readFileBytes(CLI_DATAFILE));
4444
} catch (IOException e) {

modules/cli-module/src/main/java/org/simplejavamail/internal/clisupport/serialization/SerializationUtil.java

-12
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import com.esotericsoftware.kryo.Kryo;
44
import com.esotericsoftware.kryo.io.Input;
55
import com.esotericsoftware.kryo.io.Output;
6-
import com.esotericsoftware.kryo.serializers.FieldSerializer;
7-
import com.esotericsoftware.kryo.serializers.JavaSerializer;
86
import com.esotericsoftware.kryo.util.DefaultInstantiatorStrategy;
97
import de.javakaffee.kryoserializers.UnmodifiableCollectionsSerializer;
108
import org.jetbrains.annotations.NotNull;
@@ -29,20 +27,10 @@ private static Kryo initKryo() {
2927
Kryo kryo = new Kryo();
3028
kryo.setRegistrationRequired(false);
3129
kryo.setInstantiatorStrategy(new DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
32-
// final FieldSerializer.FieldSerializerConfig config = new FieldSerializer.FieldSerializerConfig();
33-
// config.setSerializeTransient(true);
3430
UnmodifiableCollectionsSerializer.registerSerializers(kryo);
3531
return kryo;
3632
}
3733

38-
private static <T> void registerClassSerializer(final Kryo kryo, final FieldSerializer.FieldSerializerConfig config, Class<T> type) {
39-
kryo.register(type, new FieldSerializer<T>(kryo, type, config));
40-
}
41-
42-
private static <T> void registerClassJavaSerializer(final Kryo kryo, Class<T> type) {
43-
kryo.register(type, new JavaSerializer());
44-
}
45-
4634
@NotNull
4735
public static byte[] serialize(@NotNull final Object serializable)
4836
throws IOException {

0 commit comments

Comments
 (0)