Force Spring Boot to use Gson instead of Jackson

Well, WebMvcConfigurerAdapter is deprecated. As of Spring 5.0 do this:

@SpringBootApplication(exclude = {JacksonAutoConfiguration.class})
public class Spring01Application {

    public static void main(String[] args) {
        SpringApplication.run(Spring01Application.class, args);
    }

}
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Bean
    public Gson gson() {
        GsonBuilder b = new GsonBuilder();
        b.registerTypeAdapterFactory(HibernateProxyTypeAdapter.FACTORY);
        b.registerTypeAdapterFactory(DateTypeAdapter.FACTORY);
        b.registerTypeAdapterFactory(TimestampTypeAdapter.FACTORY);
        b.registerTypeAdapterFactory(LocalDateTypeAdapter.FACTORY);
        b.registerTypeAdapterFactory(LocalDateTimeTypeAdapter.FACTORY);
        return b.create();
    }

    @Override
    public void configureMessageConverters(
        List<HttpMessageConverter<?>> converters) {
        StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
        stringConverter.setWriteAcceptCharset(false);
        stringConverter.setSupportedMediaTypes(Collections
            .singletonList(MediaType.TEXT_PLAIN));
        converters.add(stringConverter);
        converters.add(new ByteArrayHttpMessageConverter());
        converters.add(new SourceHttpMessageConverter<>());
        GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter();
        gsonHttpMessageConverter.setGson(gson());
        gsonHttpMessageConverter.setSupportedMediaTypes(Arrays
            .asList(MediaType.APPLICATION_JSON));
        converters.add(gsonHttpMessageConverter);
    }
}

References
https://stackoverflow.com/questions/40786366/force-spring-boot-to-use-gson-instead-of-jackson

Parallel foreach in Java

List<Integer> listOfNumbers = Arrays.asList(1, 2, 3, 4);
listOfNumbers.parallelStream().forEach(number ->
    System.out.println(number + " " + Thread.currentThread().getName())
);

Custom Thread Pool

List<Integer> listOfNumbers = Arrays.asList(1, 2, 3, 4);
ForkJoinPool customThreadPool = new ForkJoinPool(4);
int sum = customThreadPool.submit(
    () -> listOfNumbers.parallelStream().reduce(0, Integer::sum)).get();
customThreadPool.shutdown();
assertThat(sum).isEqualTo(10);

References
https://www.baeldung.com/java-when-to-use-parallel-stream

Configuring Quartz Scheduler in Spring Boot

QuartzConfig.java

@Configuration
public class QuartzConfig {

    @Bean
    public JobDetailFactoryBean jobDetail() {
        JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
        jobDetailFactory.setJobClass(GarbageCollectorJob.class);
        jobDetailFactory.setDescription("Invoke Sample Job service...");
        jobDetailFactory.setDurability(true);
        return jobDetailFactory;
    }

    @Bean
    public SimpleTriggerFactoryBean trigger(JobDetail job) {
        SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
        trigger.setJobDetail(job);
        // every one hour
        trigger.setRepeatInterval(60 * 60 * 1000);
        trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
        return trigger;
    }

    @Bean
    public SchedulerFactoryBean scheduler(Trigger trigger, JobDetail job, JobFactory springBeanJobFactory) {
        SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
        schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));

        schedulerFactory.setJobFactory(springBeanJobFactory);
        schedulerFactory.setJobDetails(job);
        schedulerFactory.setTriggers(trigger);
        return schedulerFactory;
    }

    @Bean
    public SpringBeanJobFactory springBeanJobFactory(ApplicationContext applicationContext) {
        AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        return jobFactory;
    }
}

AutoWiringSpringBeanJobFactory.java

public final class AutoWiringSpringBeanJobFactory
        extends SpringBeanJobFactory
        implements ApplicationContextAware {

    private transient AutowireCapableBeanFactory beanFactory;

    public void setApplicationContext(
            final ApplicationContext context) {
        beanFactory = context.getAutowireCapableBeanFactory();
    }

    @Override
    protected Object createJobInstance(
            final TriggerFiredBundle bundle)
            throws Exception {
        final Object job = super.createJobInstance(bundle);
        beanFactory.autowireBean(job);
        return job;
    }
}

quartz.properties

org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=10
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true

org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore

References
https://www.baeldung.com/spring-quartz-schedule
http://www.btmatthews.com/blog/2011/inject-application-context+dependencies-in-quartz-job-beans.html
https://www.candidjava.com/spring-boot/quartz-example/

Spring Boot – Multiple Spring Data modules found, entering strict repository configuration mode

@EnableJpaRepositories(basePackages = {"com.ecommerce.core.repository.jpa"})
@EnableElasticsearchRepositories(basePackages= {"com.ecommerce.core.repository.elastic"})
@EnableRedisRepositories(basePackages = {"org.springframework.data.redis.connection.jedis"})

Since we are explicitly enabling the repositories on specific packages we can include this in the application.properties to avoid these errors:

spring.data.redis.repositories.enabled=false

We can do the same for the other repositories as well. If you encounter similar errors:

spring.data.elasticsearch.repositories.enabled=false
spring.data.jpa.repositories.enabled=false

References
https://stackoverflow.com/questions/47002094/spring-multiple-spring-data-modules-found-entering-strict-repository-configur

Using container class in Tailwind CSS

The container class sets the max-width of an element to match the min-width of the current breakpoint. This is useful if you’d prefer to design for a fixed set of screen sizes instead of trying to accommodate a fully fluid viewport.

Note that unlike containers you might have used in other frameworks, Tailwind’s container does not center itself automatically and does not have any built-in horizontal padding.

<div class="container mx-auto px-4">
  <!-- ... -->
</div>

References
https://tailwindcss.com/docs/container

Serialize and Deserialize Joda Time in Gson

register a TypeAdapter with GSON to wrap the use of a Joda preconfigured Formatters :

    public static Gson gsonDateTime() {
    Gson gson = new GsonBuilder()
            .registerTypeAdapter(DateTime.class, new JsonSerializer<DateTime>() {
                @Override
                public JsonElement serialize(DateTime json, Type typeOfSrc, JsonSerializationContext context) {
                    return new JsonPrimitive(ISODateTimeFormat.dateTime().print(json));
                }
            })
            .registerTypeAdapter(DateTime.class, new JsonDeserializer<DateTime>() {
                @Override
                public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                    DateTime dt = ISODateTimeFormat.dateTime().parseDateTime(json.getAsString());
                    return dt;
                }
            })
            .create();
    return gson;
}

References
https://stackoverflow.com/questions/14996663/is-there-a-standard-implementation-for-a-gson-joda-time-serialiser

Spring Data MongoDB Transactions

MongoDB Configuration

@Configuration
@EnableMongoRepositories(basePackages = "com.baeldung.repository")
public class MongoConfig extends AbstractMongoClientConfiguration{

    @Bean
    MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
        return new MongoTransactionManager(dbFactory);
    }

    @Override
    protected String getDatabaseName() {
        return "test";
    }

    @Override
    public MongoClient mongoClient() {
        final ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test");
        final MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
            .applyConnectionString(connectionString)
            .build();
        return MongoClients.create(mongoClientSettings);
    }
}

Synchronous Transactions

@Test
@Transactional
public void whenPerformMongoTransaction_thenSuccess() {
    userRepository.save(new User("John", 30));
    userRepository.save(new User("Ringo", 35));
    Query query = new Query().addCriteria(Criteria.where("name").is("John"));
    List<User> users = mongoTemplate.find(query, User.class);

    assertThat(users.size(), is(1));
}

Note that we can’t use listCollections command inside a multi-document transaction – for example:

References
https://www.baeldung.com/spring-data-mongodb-transactions

async / await in TypeScript

"use strict";
// printDelayed is a 'Promise<void>'
async function printDelayed(elements: string[]) {
  for (const element of elements) {
    await delay(400);
    console.log(element);
  }
}
async function delay(milliseconds: number) {
  return new Promise<void>((resolve) => {
    setTimeout(resolve, milliseconds);
  });
}
printDelayed(["Hello", "beautiful", "asynchronous", "world"]).then(() => {
  console.log();
  console.log("Printed every element!");
});

References
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-7.html