Reputation: 11679
I have two proceses on which I need to validate on few fields.
ProcessA
class, I need to validate on few fields. Basis on those fields I will validate this class.ProcessB
class, I need to validate on different fields. And if those fields are valid, then I will validate this class.Both my processes should pass GenericRecord
to Validator
class and now depending on whether it is ProcessA
or ProcessB
, my Validator
class should validate those fields.
clientId
, deviceId
, payId
.crossId
, maxId
, minId
.I am able to make it work for ProcessA but I am confuse how does my Validator
class will look like for ProcessB
fields validation. Confusion is how does Validator
class decide that I need to validate fields for ProcessA or ProcessB as soon as it receives GenericRecord
in the constructor. If ProcessA
GenericRecord is passed, then do validation on ProcessA fields or If ProcessB
GenericRecord is passed, then do validation on ProcessB fields.
ProcessA
try {
GenericRecordDomainDataDecoder decoder = new GenericRecordDomainDataDecoder(config);
while (true) {
ConsumerRecords<byte[], byte[]> records = consumer.poll(1000);
for (ConsumerRecord<byte[], byte[]> record : records) {
GenericRecord payload = decoder.decode(record.value());
String processName = "processA";
// validation logic
Validator validation = new Validator(payload);
if(!validation.isValid())
continue;
// some other code
}
}
} catch (Exception ex) {
// logging error
}
ProcessB
try {
GenericRecordDomainDataDecoder decoder = new GenericRecordDomainDataDecoder(config);
while (true) {
ConsumerRecords<byte[], byte[]> records = consumer.poll(1000);
for (ConsumerRecord<byte[], byte[]> record : records) {
GenericRecord payload = decoder.decode(record.value());
String processName = "processB";
// validation logic
Validator validation = new Validator(payload);
if(!validation.isValid())
continue;
// some other code
}
}
} catch (Exception ex) {
// logging error
}
Below is my Validator class which only works right now for ProcessA
validation. I have added another constructor which I know doesn't work but just wanted to show what I want to do for ProcessB
. And then I need to call isValid
method that will tell me whether fields for ProcessB are present or not.
public class Validator {
private String clientId, deviceId, payId;
// for ProcessA
public Validator(GenericRecord payload) {
clientId = (String) DataUtils.parseRecord(payload, "clientId");
deviceId = (String) DataUtils.parseRecord(payload, "deviceId");
payId = (String) DataUtils.parseRecord(payload, "payId");
}
// for ProcessB, I know this doesn't work - just wanted to show the idea
public Validator(GenericRecord payload) {
crossId = (String) DataUtils.parseRecord(payload, "crossId");
maxId = (String) DataUtils.parseRecord(payload, "maxId");
minId = (String) DataUtils.parseRecord(payload, "minId");
}
// this is what I am calling for ProcessA
public boolean isValid() {
return isValidClientIdDeviceId() && isValidPayId();
}
private boolean isValidPayId() {
if (payId == null) {
logger.log("invalid payId.");
return false;
}
return true;
}
private boolean isValidClientIdDeviceId() {
if (clientId == null && deviceId == null) {
logger.log("invalid clientId and deviceId.");
return false;
}
return true;
}
// getters
}
I can pass another parameter processName
which is a String to Validator
class. Can we use that to achieve this to validate fields accordingly.
Upvotes: 1
Views: 183
Reputation: 131346
The first solution I propose to you is acceptable if you have few of type of Process class.
You could have a empty constructor and have a init method by Process you invoke after the constructor.
Just keep the default constructor (don't need to declare that):
public Validator() {
}
// for ProcessA
public initProcessA(GenericRecord payload) {
clientId = (String) DataUtils.parseRecord(payload, "clientId");
deviceId = (String) DataUtils.parseRecord(payload, "deviceId");
payId = (String) DataUtils.parseRecord(payload, "payId");
}
// for ProcessB,
public void initProcessB(GenericRecord payload) {
crossId = (String) DataUtils.parseRecord(payload, "crossId");
maxId = (String) DataUtils.parseRecord(payload, "maxId");
minId = (String) DataUtils.parseRecord(payload, "minId");
}
In Process A :
Validator validation = new Validator();
validation.initProcessA(payload);
In Process B :
Validator validation = new Validator();
validation.initProcessB(payload);
This first solution has its limits.
If you have validation specificities that depends on the Process
class, a better solution would be to explode the rules with a distinct validator class for each Process because it would be more maintainable.
You could have for example :
public abstract class Validator<T extends Process>{
...
// common and abstract methods
...
public abstract boolean isValid();
}
Validator A for Process A :
public class ValidatorA extends Validator<ProcessA>{
...
public ValidatorA(GenericRecord payload){
clientId = (String) DataUtils.parseRecord(payload, "clientId");
deviceId = (String) DataUtils.parseRecord(payload, "deviceId");
payId = (String) DataUtils.parseRecord(payload, "payId");
}
public boolean isValid(){
// validation rules specific to ProcessA
}
...
}
Validator B for Process B :
public class ValidatorB extends Validator<ProcessB>{
...
public ValidatorB(GenericRecord payload) {
crossId = (String) DataUtils.parseRecord(payload, "crossId");
maxId = (String) DataUtils.parseRecord(payload, "maxId");
minId = (String) DataUtils.parseRecord(payload, "minId");
}
public boolean isValid(){
// validation rules specific to ProcessB
}
...
}
Upvotes: 1