Prevent to start spring-boot application if enum valitiation fails - java

I want to prevent my application from starting if my enum method for validation uniqueness of a field fails.
public enum MyEnum {
VALUE_1(1),
VALUE_2(1), //same code as VALUE_1 is forbidden
VALUE_3(3),
;
private int code;
static { //this method is called only when 1st time acessing an inscance of this enum, I want it to be executed upon spring boot initialization and when it fails stop appliacation
long uniqueCodesCount = Arrays.stream(MyEnum.values()).map(MyEnum::getCode)
.distinct()
.count();
if (MyEnum.values().length != uniqueCodesCount) {
throw new RuntimeException("Not unique codes");
}
}
}

Just keep it simple. For example convert the verification to a static method:
public enum MyEnum {
...
public static void verifyUniqueness() {
long uniqueCodesCount = Arrays.stream(MyEnum.values()).map(MyEnum::getCode)
.distinct()
.count();
if (MyEnum.values().length != uniqueCodesCount) {
throw new RuntimeException("Not unique codes");
}
}
}
Then you may implement InitializingBean in a bean and override the method afterPropertiesSet(). E.g. suppose your application is called DemoApplication, it will look like this:
#SpringBootApplication
public class DemoApplication implements InitializingBean {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
public void afterPropertiesSet() throws Exception {
MyEnum.verifyUniqueness();
}
}
From the documentation of InitializingBean:
Interface to be implemented by beans that need to react once all their properties have been set by a BeanFactory: e.g. to perform custom initialization, or merely to check that all mandatory properties have been set.

Related

Ways to Avoid if-else, switch-case in Factory design pattern

I am designing a validation module. It has 100 error codes(i.e. errcd_01, errcd_02,..,errcd_100) to be validated. In input I am getting a specific error code(i.e. errcd_01) out of above 100.
Module should perform validation for that specific error code.
I am using factory pattern.
/* Interface */
public interface validateErrCd {
void check_errcd();
}
/* Concrete classes implementing the same interface */
public class validateErrCd_01 implements validateErrCd {
#Override
public void check_errcd() {
//business logic related to errcd_01
}
}
public class validateErrCd_02 implements validateErrCd {
#Override
public void check_errcd() {
//business logic related to errcd_02
}
}
.
.
.
public class validateErrCd_100 implements validateErrCd {
#Override
public void check_errcd() {
//business logic related to errcd_100
}
}
/* Factory */
public class ErrorValidationFactory {
//use check_errcd method to get object of type shape
public validateErrCd getValidation(String errorCode){
if(errorCode == null){
return null;
}
if(errorCode.equalsIgnoreCase("errcd_01")){
return new validateErrCd_01();
} else if(errorCode.equalsIgnoreCase("errcd_02")){
return new validateErrCd_02();
} ..
.......
else if(errorCode.equalsIgnoreCase("errcd_100")){
return new validateErrCd_100();
}
else {
return null;
}
}
}
/* I am using the Factory to get object of concrete class by passing an specific error code to be validated (i.e. "errcd_01"). */
public class FactoryPatternDemo {
public static void main(String[] args) {
ErrorValidationFactory errorFactory = new ErrorValidationFactory();
//get an object of validateErrCd_01 and call its check_errcd method.
validateErrCd errcd01 = errorFactory.getValidation("errcd_01");
//call check_errcd method of validateErrCd_01
errcd01.check_errcd();
}
}
Now due to multiple if/else inside Factory class ErrorValidationFactory, I am getting couple of CI/CD errors while performing mvn clean install.
e.g. [MethodLength] - checkstyle, Rule:CyclomaticComplexity - PMD.
So is there a way I can replace if/else, switch case kind of decision making inside factory which does not trigger above CI/CD errors in Java?
Note : If possible I would like to avoid reflection
You could use a Map:
public class ErrorValidationFactory {
private Map<String,Supplier<validateErrCd>> creators=new HashMap<>();
public ErrorValidationFactory(){
creators.put("errcd_100",validateErrCd_100::new);
//Same for others
}
//use check_errcd method to get object of type shape
public validateErrCd getValidation(String errorCode){
if(errorCode == null){
return null;
}
return creators.getOrDefault(errorCode,()->null);
}
}
Supplier is a functional interface that contains a method returning an object. SomeClass::new or ()->new SomeClass() means that the constructor of the class will be used for that.
This allows to to create the instances later.
If you want to create the Map only once, you can make it static and populate it in a static initializer.
However, if you really want to dynamically get the constructors, you would need to use reflection.

How to pass parameters from one lambda to another in java?

I want to invoke Lambda function A from another lambda function B with some parameters.
The following is the invoking lambda function.
#SpringBootApplication
public class Application extends SpringBootServletInitializer implements CommandLineRunner {
#Autowired
private ConfigurableApplicationContext context;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void run(String... args) {
DCService dcService = LambdaInvokerFactory.builder().lambdaFunctionNameResolver(
(method, lambdaFunction, lambdaInvokerFactoryConfig) -> "EventPlanDCFunction-Dev")
.build(DCService.class);
log.info("Response from DC service :: {}",dcService.getClass());
String[] params = new String[]{"Subir has invoked"};
dcService.run(params);
SpringApplication.exit(context);
}
}
following is the code of DCService.java file.
public interface DCService {
#LambdaFunction(functionName = "DeliveryCycleLambdaHandler",
invocationType = InvocationType.Event)
void run(String... params);
}
The following is the code of the lambda function which I want to invoke.
#SpringBootApplication
public class Application extends SpringBootServletInitializer implements CommandLineRunner {
#Autowired
private ConfigurableApplicationContext context;
#Autowired
private DeliveryCycleService deliveryCycleService;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void run(String... args) {
deliveryCycleService.printMessage(args[0]);
SpringApplication.exit(context);
}
}
As you can see, I tried to pass the parameter by creating an array of String from the invoking method but I am getting ArrayOutOFBoundException in the other method meaning the parameter is not actually reaching the invoked method. If I do not pass parameter it works fine but for my use case, I need to pass parameter and invoke the method asynchronously.
NOTE: The lambdaHandle code is same for both of them. The following belongs to one of them.
#Slf4j
public class DCInvokeHandler implements RequestStreamHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(DCInvokeHandler.class);
private volatile SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
#Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
if (handler == null) {
synchronized (this) {
if (handler == null) {
handler = initHandler();
}
}
}
handler.proxyStream(inputStream, outputStream, context);
}
private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> initHandler() {
try {
return SpringBootLambdaContainerHandler.getAwsProxyHandler(Application.class, Env.getEnv().name());
} catch (ContainerInitializationException e) {
LOGGER.error("Failed to start spring boot lambda handler", e);
// if we fail here. We re-throw the exception to force another cold start
throw new IllegalStateException("Could not initialize Spring Boot application", e);
}
}
}
This is the basic code to invoke another lambda from a lambda function.aws sdk doc
try {
InvokeRequest invokeRequest = new InvokeRequest();
invokeRequest.setFunctionName(FunctionName);
invokeRequest.setPayload(ipInput);
returnDetails = byteBufferToString(
lambdaClient.invoke(invokeRequest).getPayload(),
Charset.forName("UTF-8"),logger);
} catch (Exception e) {
logger.log(e.getMessage());
}
To invoke the another lambda function asynchronously, set InvocationType to Event.aws api docs
Following are the invocation type RequestResponse, Event, DryRun.
RequestResponse (default) - Invoke the function synchronously. Keep the connection open until the function returns a response or times out. The API response includes the function response and additional data.
Event - Invoke the function asynchronously. Send events that fail multiple times to the function's dead-letter queue (if it's configured). The API response only includes a status code.
DryRun - Validate parameter values and verify that the user or role has permission to invoke the function.

How to map a list of Java exceptions to customer visible error codes

I'm designing a Java exception handling mechanism for a 2 component system {front-end, back-end}. The back-end will generate exceptions by using Exception classes for different error conditions. Front-end has to map those exception classes to a customer visible error code. This list of Exception classes can be pretty big and may continue to increase in size. What is the best way to map those Exception classes to customer visible error codes?
I could create a Map<Class, Integer> MAP_EX_CLASS_TO_ERROR_CODE and keep it updated, but is it the right/scalable way to map exceptions?
------- Edits after receiving initial set of answers, see Comments below ----
I want to represent similar types of exceptions, or exceptions that demand similar handling with one exception class. For e.g. UserExceptions can be:
RESOURCE_NAME_TOO_LONG
RESOURCE_NOT_FOUND
RESOURCE_NOT_OWNED
...
and InternalExceptions can be:
SERVER_UNAVAILABLE
REQUEST_TIMEOUT
...
If I make an enum for all these error codes, then is it still useful to implement the grouping? I wanted to do the grouping instead of defining one single class for checked exceptions because it'll force me to pay attention to the catch-ing of exceptions every time I add a new line of code that throws a different checked exception than existing code.
for e.g.
public enum ECodes {
RESOURCE_NAME_TOO_LONG(/*number*/0, UserException.class),
RESOURCE_NOT_FOUND(1, UserException.class),
RESOURCE_NOT_OWNED(2, UserException.class),
SERVER_UNAVAILABLE(3, InternalException.class),
REQUEST_TIMEOUT(4, InternalException.class);
// constructor and stuff
}
public class Prot1ExceptionMapper {
static Map<Ecode, /*CustomerCode*/Integer> MAP_EX_CLASS_TO_ERROR_CODE = new HashMap<>();
static {
MAP_EX_CLASS_TO_ERROR_CODE.add(Ecode.RESOURCE_NAME_TOO_LONG, PROT1_CUSTOMER_CODE1);
// Other mappings here
}
public static Integer map(Ecode ecode) {
// Lookup ecode
}
}
public class Prot2ExceptionMapper {
static Map<Ecode, /*CustomerCode*/Integer> MAP_EX_CLASS_TO_ERROR_CODE = new HashMap<>();
static {
MAP_EX_CLASS_TO_ERROR_CODE.add(Ecode.RESOURCE_NAME_TOO_LONG, PROT2_CUSTOMER_CODE1);
// Other mappings here
}
public static Integer map(Ecode ecode) {
// Lookup ecode
}
}
public class UserException extends Exception {
public UserException(ECodes ecode, String message) {
assert ecode.class == UserException.class;
}
}
public class InternalException extends Exception {
public InternalException(ECodes ecode, String message) {
assert ecode.class == UserException.class;
}
}
class DummyClass {
public void doFirstJob() throws UserException {}
public void doSecondJob() throws InternalException {}
}
class Protocol1MainClass {
public static void main(final String[] args) {
try {
doFirstJob();
doSecondJob();
} catch (UserException e1) {
// Do UserException specific stuff
throw Prot1ExceptionMapper.map(e1);
} catch (InternalException e2) {
// Do InternalException specific stuff
throw Prot1ExceptionMapper.map(e2);
}

Java - How to test exception which never will occur?

I have Utils class with method which throws exception when given data are incorrect.
I have also Service which uses this method, but the data are always generated in way that they will be correct during call. Data are generated by another utils class.
I understand that I should throw this exception from Utils class - but I can't throw it from Service - so I have to catch it.
How can I test this, simulate this exception?
All actions on this data are in private methods.
I want to avoid PowerMock, because I heard that it's a sign of bad design.
So the question is, how to implement this in good design?
From your description it looks like this:
class Service {
public void someMethod() {
Data data = AnotherUtils.getData();
try {
Utils.method(data); // exception never thrown
} catch(Exception e) {
// how to test this branch?
}
}
}
The goal would be something like this:
interface DataProvider {
Data getData();
}
interface DataConsumer {
void method(Data data);
}
class Service {
private final DataProvider dataProvider;
private final DataConsumer dataConsumer;
public Service(DataProvider dataProvider, DataConsumer dataConsumer) {...}
public void someMethod() {
Data d = dataProvider.getData();
try {
dataConsumer.method(data);
} catch(Exception e) {
}
}
}
This technique is called dependency injection.
Then, when testing, you can simply provide a mock implementation for this DataProvider interface that does return faulty data:
#Test(expected=Exception.class)
public void myTest() {
DataProvider badDataProvider = () -> new BadData(); // Returns faulty data
Service service = new Service(badDataProvider, Utils.getConsumer());
service.someMethod(); // boom!
}
For the non-testing code, you could simply wrap the utils classes you already have in these interfaces:
class AnotherUtils {
public static Data getData() {...}
public static DataProvider getProvider() {
return AnotherUtils::getData;
}
}
...
Service service = new Service(AnotherUtils.getProvider(), Utils.getConsumer());
Here is an approach where you want to introduce Dependency Injection, but for whatever reason you don't want to change legacy code.
Say you have some static utility method like so:
class Utils{
public static Something aMethod(SomethingElse input) throws AnException{
if(input.isValid())
return input.toSomething();
throw new AnException("yadda yadda");
}
}
And you have a class that uses that utility method. You can still inject it with a FunctionalInterface.
#FunctionalInterface
interface FunctionThrowsAnException<K,V> {
V apply(K input) throws AnException;
}
class Service {
private final FunctionThrowsAnException<SomethingElse,Something> func;
Service(FunctionThrowsAnException<SomethingElse,Something> func){
this.func = func;
}
Something aMethod(SomethingElse input){
try{
return func.apply(input);
}catch(AnException ex){
LOGGER.error(ex);
}
}
}
Then use it like this:
new Service(Utils::aMethod).aMethod(input);
To test it:
new Service(x -> { throw new AnException("HA HA"); }).aMethod(input);

SpringBoot validation of a bean method parameters and return

I can't make method level validation right. Or I don't understand how it works.
My application class is below. Very simple. It contains MethodValidationPostProcessor bean definition. It also runs Greeter service.
#SpringBootApplication
public class App implements CommandLineRunner {
private final Greeter greeter;
public App(Greeter greeter) {
this.greeter = greeter;
}
public static void main(String[] args) {
new SpringApplicationBuilder().main(App.class).sources(App.class).web(false).run(args).close();
}
#Bean
public org.springframework.validation.beanvalidation.MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
#Override
public void run(String... args) throws Exception {
final Input input = new Input();
input.setName("j");
final String messageFromInput = greeter.getMessageFromInput(input);
final String messageFromString = greeter.getMessageFromString("j");
}
}
Greeter service below. Here I do expect to validate input and output.
#Service
#Validated
public class Greeter {
String getMessageFromInput(#Valid #NotNull Input name) {
return "[From Input] Greetings! Oh mighty " + name + "!";
}
String getMessageFromString(#Size(min = 4) String name) {
return "[From String] Greetings! Oh mighty " + name + "!";
}
}
Input DTO is very simple as well.
public class Input {
#NotEmpty
#Size(min = 3)
private String name;
// Getters, setters and toString ommited.
}
Since the name in both cases, direct String and DTO, is only one letter I expect this setup to throw exception. Unfortunately, nothing happens and application completes successfully. It works with controller's methods. But I would like it to work with any bean's methods.
You are injecting your Greeter bean as a constructor argument into the class annotated with #SpringBootApplication which is a #Configuration class. To satisfy that dependency the Greeter is created very early on in the startup process of the ApplicationContext and as such will remove it as a candidate for proxy creation.
Instead of injecting it as a constructor argument move your CommandLineRunner logic to a #Bean annotated method and simply inject the Greeter as a dependency. This will delay the creation of the bean and as such make it available for proxying.
#Bean
public CommandLineRunner runner(Greeter greeter) {
return new CommandLineRunner() {
#Override
public void run(String... args) throws Exception {
final Input input = new Input();
input.setName("j");
final String messageFromInput = greeter.getMessageFromInput(input);
final String messageFromString = greeter.getMessageFromString("j");
}
};
}
Another thing is that your methods of the Greeter should be, due the the nature of proxies, public.

Categories