Skip to content

Commit

Permalink
Add support to use any type as a job parameter
Browse files Browse the repository at this point in the history
This commit also changes the way job parameters
are parsed and persisted.

NB: This commit should ideally have been split
into two change sets. But the changes are tightly
related that is was not possible to separate them.

Related to:

* spring-projects#3960
* spring-projects#2122
* spring-projects#1035
* spring-projects#1983
  • Loading branch information
fmbenhassine committed Oct 4, 2022
1 parent 0273024 commit 34cf4d7
Show file tree
Hide file tree
Showing 69 changed files with 2,482 additions and 901 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ public class DefaultJobKeyGenerator implements JobKeyGenerator<JobParameters> {
public String generateKey(JobParameters source) {

Assert.notNull(source, "source must not be null");
Map<String, JobParameter> props = source.getParameters();
Map<String, JobParameter<?>> props = source.getParameters();
StringBuilder stringBuffer = new StringBuilder();
List<String> keys = new ArrayList<>(props.keySet());
Collections.sort(keys);
for (String key : keys) {
JobParameter jobParameter = props.get(key);
JobParameter<?> jobParameter = props.get(key);
if (jobParameter.isIdentifying()) {
String value = jobParameter.getValue() == null ? "" : jobParameter.toString();
String value = jobParameter.toString();
stringBuffer.append(key).append("=").append(value).append(";");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@
package org.springframework.batch.core;

import java.io.Serializable;
import java.util.Date;

import org.springframework.lang.NonNull;
import org.springframework.util.Assert;

/**
* Domain representation of a parameter to a batch job. Only the following types can be
* parameters: String, Long, Date, and Double. The identifying flag is used to indicate if
* the parameter is to be used as part of the identification of a job instance.
* Domain representation of a parameter to a batch job. The identifying flag is used to
* indicate if the parameter is to be used as part of the identification of a job
* instance.
*
* @author Lucas Ward
* @author Dave Syer
Expand All @@ -34,87 +33,35 @@
* @since 2.0
*
*/
public class JobParameter implements Serializable {
public class JobParameter<T> implements Serializable {

private final Object parameter;
private T value;

private final ParameterType parameterType;
private Class<T> type;

private final boolean identifying;
private boolean identifying;

/**
* Construct a new {@code JobParameter} from a {@link String}.
* @param parameter {@link String} instance. Must not be {@code null}.
* @param identifying {@code true} if the {@code JobParameter} should be identifying.
* reate a new {@link JobParameter}.
* @param value the value of the parameter. Must not be {@code null}.
* @param type the type of the parameter. Must not be {@code null}.
* @param identifying true if the parameter is identifying. false otherwise.
*/
public JobParameter(@NonNull String parameter, boolean identifying) {
this(parameter, identifying, ParameterType.STRING);
}

/**
* Construct a new {@code JobParameter} from a {@link Long}.
* @param parameter {@link Long} instance. Must not be {@code null}.
* @param identifying {@code true} if the {@code JobParameter} should be identifying.
*/
public JobParameter(@NonNull Long parameter, boolean identifying) {
this(parameter, identifying, ParameterType.LONG);
}

/**
* Construct a new {@code JobParameter} from a {@link Date}.
* @param parameter {@link Date} instance. Must not be {@code null}.
* @param identifying {@code true} if the {@code JobParameter} should be identifying.
*/
public JobParameter(@NonNull Date parameter, boolean identifying) {
this(parameter, identifying, ParameterType.DATE);
}

/**
* Construct a new {@code JobParameter} from a {@link Double}.
* @param parameter {@link Double} instance. Must not be {@code null}.
* @param identifying {@code true} if the {@code JobParameter} should be identifying.
*/
public JobParameter(@NonNull Double parameter, boolean identifying) {
this(parameter, identifying, ParameterType.DOUBLE);
}

private JobParameter(Object parameter, boolean identifying, ParameterType parameterType) {
Assert.notNull(parameter, "parameter must not be null");
this.parameter = parameter;
this.parameterType = parameterType;
public JobParameter(@NonNull T value, @NonNull Class<T> type, boolean identifying) {
Assert.notNull(value, "value must not be null");
Assert.notNull(value, "type must not be null");
this.value = value;
this.type = type;
this.identifying = identifying;
}

/**
* Construct a new {@code JobParameter} from a {@link String}.
* @param parameter A {@link String} instance.
* Create a new identifying {@link JobParameter}.
* @param value the value of the parameter. Must not be {@code null}.
* @param type the type of the parameter. Must not be {@code null}.
*/
public JobParameter(String parameter) {
this(parameter, true);
}

/**
* Construct a new {@code JobParameter} from a {@link Long}.
* @param parameter A {@link Long} instance.
*/
public JobParameter(Long parameter) {
this(parameter, true);
}

/**
* Construct a new {@code JobParameter} as a {@link Date}.
* @param parameter A {@link Date} instance.
*/
public JobParameter(Date parameter) {
this(parameter, true);
}

/**
* Construct a new {@code JobParameter} from a {@link Double}.
* @param parameter A {@link Double} instance.
*/
public JobParameter(Double parameter) {
this(parameter, true);
public JobParameter(@NonNull T value, @NonNull Class<T> type) {
this(value, type, true);
}

/**
Expand All @@ -128,15 +75,16 @@ public boolean isIdentifying() {
/**
* @return the value contained within this {@code JobParameter}.
*/
public Object getValue() {
return parameter;
public T getValue() {
return value;
}

/**
* @return a {@link ParameterType} representing the type of this parameter.
* Return the type of the parameter.
* @return the type of the parameter
*/
public ParameterType getType() {
return parameterType;
public Class<T> getType() {
return type;
}

@Override
Expand All @@ -150,41 +98,17 @@ public boolean equals(Object obj) {
}

JobParameter rhs = (JobParameter) obj;
return parameterType == rhs.parameterType && parameter.equals(rhs.parameter);
return type == rhs.type && value.equals(rhs.value);
}

@Override
public String toString() {
return parameterType == ParameterType.DATE ? "" + ((Date) parameter).getTime() : parameter.toString();
return "{" + "value=" + value + ", type=" + type + ", identifying=" + identifying + '}';
}

@Override
public int hashCode() {
return 7 + 21 * parameter.hashCode();
}

/**
* Enumeration representing the type of {@link JobParameter}.
*/
public enum ParameterType {

/**
* String parameter type.
*/
STRING,
/**
* Date parameter type.
*/
DATE,
/**
* Long parameter type.
*/
LONG,
/**
* Double parameter type.
*/
DOUBLE;

return 7 + 21 * value.hashCode();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@
package org.springframework.batch.core;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

/**
* Value object representing runtime parameters to a batch job. Because the parameters
Expand All @@ -46,7 +49,7 @@
@SuppressWarnings("serial")
public class JobParameters implements Serializable {

private final Map<String, JobParameter> parameters;
private final Map<String, JobParameter<?>> parameters;

/**
* Default constructor.
Expand All @@ -61,7 +64,7 @@ public JobParameters() {
* @param parameters The {@link Map} that contains a {@code String} key and a
* {@link JobParameter} value.
*/
public JobParameters(Map<String, JobParameter> parameters) {
public JobParameters(Map<String, JobParameter<?>> parameters) {
this.parameters = new LinkedHashMap<>(parameters);
}

Expand All @@ -75,8 +78,11 @@ public Long getLong(String key) {
if (!parameters.containsKey(key)) {
return null;
}
Object value = parameters.get(key).getValue();
return value == null ? null : ((Long) value).longValue();
JobParameter<?> jobParameter = parameters.get(key);
if (!jobParameter.getType().equals(Long.class)) {
throw new IllegalArgumentException("Key " + key + " is not of type Long");
}
return (Long) jobParameter.getValue();
}

/**
Expand Down Expand Up @@ -104,8 +110,14 @@ public Long getLong(String key, @Nullable Long defaultValue) {
*/
@Nullable
public String getString(String key) {
JobParameter value = parameters.get(key);
return value == null ? null : value.toString();
if (!parameters.containsKey(key)) {
return null;
}
JobParameter<?> jobParameter = parameters.get(key);
if (!jobParameter.getType().equals(String.class)) {
throw new IllegalArgumentException("Key " + key + " is not of type String");
}
return (String) jobParameter.getValue();
}

/**
Expand Down Expand Up @@ -136,8 +148,11 @@ public Double getDouble(String key) {
if (!parameters.containsKey(key)) {
return null;
}
Double value = (Double) parameters.get(key).getValue();
return value == null ? null : value.doubleValue();
JobParameter<?> jobParameter = parameters.get(key);
if (!jobParameter.getType().equals(Double.class)) {
throw new IllegalArgumentException("Key " + key + " is not of type Double");
}
return (Double) jobParameter.getValue();
}

/**
Expand Down Expand Up @@ -165,7 +180,14 @@ public Double getDouble(String key, @Nullable Double defaultValue) {
*/
@Nullable
public Date getDate(String key) {
return this.getDate(key, null);
if (!parameters.containsKey(key)) {
return null;
}
JobParameter<?> jobParameter = parameters.get(key);
if (!jobParameter.getType().equals(Date.class)) {
throw new IllegalArgumentException("Key " + key + " is not of type java.util.Date");
}
return (Date) jobParameter.getValue();
}

/**
Expand All @@ -179,19 +201,24 @@ public Date getDate(String key) {
@Nullable
public Date getDate(String key, @Nullable Date defaultValue) {
if (parameters.containsKey(key)) {
return (Date) parameters.get(key).getValue();
return getDate(key);
}
else {
return defaultValue;
}
}

@Nullable
public JobParameter<?> getParameter(String key) {
Assert.notNull(key, "key must not be null");
return parameters.get(key);
}

/**
* Get a map of all parameters, including {@link String}, {@link Long}, and
* {@link Date} types.
* Get a map of all parameters.
* @return an unmodifiable map containing all parameters.
*/
public Map<String, JobParameter> getParameters() {
public Map<String, JobParameter<?>> getParameters() {
return Collections.unmodifiableMap(parameters);
}

Expand Down Expand Up @@ -223,17 +250,25 @@ public int hashCode() {

@Override
public String toString() {
return parameters.toString();
List<String> parameters = new ArrayList<>();
for (Map.Entry<String, JobParameter<?>> entry : this.parameters.entrySet()) {
parameters.add(String.format("'%s':'%s'", entry.getKey(), entry.getValue()));
}
return new StringBuilder("{").append(String.join(",", parameters)).append("}").toString();
}

/**
* @return The {@link Properties} that contain the key and values for the
* {@link JobParameter} objects.
* @deprecated since 5.0, scheduled for removal in 5.2. Use
* {@link org.springframework.batch.core.converter.JobParametersConverter#getProperties(JobParameters)}
*
*/
@Deprecated(since = "5.0", forRemoval = true)
public Properties toProperties() {
Properties props = new Properties();

for (Map.Entry<String, JobParameter> param : parameters.entrySet()) {
for (Map.Entry<String, JobParameter<?>> param : parameters.entrySet()) {
if (param.getValue() != null) {
props.put(param.getKey(), Objects.toString(param.getValue().toString(), ""));
}
Expand Down
Loading

0 comments on commit 34cf4d7

Please sign in to comment.