Tag Archives: Spring Boot

[Solved]: JAXB empty Tag without xsi:nil=”true” for null values by using jaxb.properties


Generally when we do marshaling from JAVA object to XML through JAXB, the null values String or other objects not considered while marshalling and xml tag for these objects not generated.

If we need to get xml tags also for null values object then define these property in model class with attribute nillable=true.

 @XmlElement(name = "description", nillable = true)
 private String description;

After adding nillable=true property attribute this will generate output XML tag as below

<description xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>

Problem Statement

Here problem is we don’t want the XML description tag with schema url and xsi:nil=”true” as above. We want only the empty tag for XML as below

<description />

Solutions

Here the problem is when any value in model class property is found as null the JAXB does not call any xmlAdaptor and generate tag with schema link with xsi:nil=”true”.

To solve this problem we can use third party JAXB provider EclipseLink JAXB (MOXy) . It’s required to make below changes on your application and model class.

  • Add this EclipseLink MOXy dependency in you application
<dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>org.eclipse.persistence.moxy</artifactId>
        <version>2.6.8</version>
    </dependency>
  • Add XmlNullPolicy on all the fields of model where need to generate empty tag for null values.
 @XmlElement(name = "description", nillable = true)
 @XmlNullPolicy(emptyNodeRepresentsNull = true, nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE)
 private String description;
  • Now we need to set below property in our JVM while marshaling through java object to XML.
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

There are following ways to add above property based on you application need.

Solution 1: In case of simple java application, you can add this line of code before marshaling

System.setProperty("javax.xml.bind.JAXBContextFactory", "org.eclipse.persistence.jaxb.JAXBContextFactory");

Solution 2: Create jaxb.properties file in your each model package/resource folder and add below property

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Note: Once you will run your code in your local machine it will generate empty tag but you will face problem when deploy application after making maven build because this property file will not add in your generated classes folder model packages. In this case you have to add below lines of code in pom.xml to copy jaxb.properties file in model package.

<plugin>
            <artifactId>maven-resources-plugin</artifactId>
            <version>2.6</version>
            <executions>
                <execution>
                    <id>copy-resources01</id>
                    <phase>validate</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${basedir}/target/classes/model package location</outputDirectory>
                        <encoding>UTF-8</encoding>
                        <resources>
                            <resource>
                                <directory>${basedir}/src/main/resources</directory>
                                <includes>
                                    <include>jaxb.properties</include>
                                </includes>
                            </resource>
                        </resources>
                    </configuration>
                </execution>
            </executions>
        </plugin>

Solution 3: If your application is Spring boot then you can also pass the below arguments while deploying application.

-Djavax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

or

Add the property in application.properties/application.yml file

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

This solution will also help when you are having multiple packages for model classes and no need to include jaxb.properties in each package.

Conclusion

In this topic you learn about the steps to generate empty tags for XML incase null values for Java objects. you can also learn about the copy of jaxb.properties file in packages by maven. Incase of having multiple packages for model classes you can follow solutions to handle it.

Let me know about your thoughts on these solutions.

Happy Learning !!!

Spring Scheduling Annotations List


After Spring Boot, Spring enhanced with scheduling and Asynchronous annotations which added with methods along with some information about to execute it, and Spring takes care of rest.

These annotations are from the org.springframework.scheduling.annotation package. Below are most common annotations which we use at time of development:

See Also :

Spring Scheduling Annotations

@EnableAsync

@EnableAsync annotation enable asynchronous functionality in Spring. It must use with @Configuration.

@Configuration
@EnableAsync
class VehicleFactoryConfig {}

Now, that we enabled asynchronous calls, we can use @Async to define the methods supporting it.

@EnableScheduling

@EnableScheduling annotation enable scheduling in the application. We should always use it in conjunction with @Configuration:

@Configuration
@EnableScheduling
class VehicleFactoryConfig {}

Now we are enabled with Schedule, we can now run methods periodically with @Scheduled.

@Async

@Async apply on methods which we want to execute on a different thread, hence run them asynchronously.

@Async
void repairCar() {
    // ...
}

If we apply @Aynch annotation to a class, then all methods will be called asynchronously.

Note: Before applying @Async on method first we need to enabled the asynchronous calls for this annotation to work, with @EnableAsync or XML configuration.

@Scheduled

@Scheduled annotation use to execute a method periodically at fixed interval or by Cron like expressions.

For Example : The first execution of the task will be delayed by 5 seconds and then it will be executed normally at a fixed interval of 2 seconds.

@Scheduled(fixedRate = 2000 , initialDelay=5000)
void checkVehicle() {
    // ...
}

After Java 8 with repeating annotations feature, @Scheduled can mark multiple times on a method with different period or Cron expressions.

For Example : The first execution of the task will be delayed by 5 seconds and then it will be executed normally at a fixed interval of 2 seconds and cron expression will execute on Monday to Saturday on 12 PM.

@Scheduled(fixedRate = 2000)
@Scheduled(cron = "0 * * * * MON-SAT")
void checkVehicle() {
    // ...
}

Note:

  • Before applying @Scheduled on method first we need to enabled the scheduling calls by applying @EnableScheduling configuration. that the method annotated with @Scheduled should have a void return type.
  • The method having @Scheduled should have a void return type.

@Schedules

@Schedules annotation use to specify multiple @Scheduled rules.

@Schedules({
  @Scheduled(fixedRate = 2000),
  @Scheduled(cron = "0 * * * * MON-SAT")
})
void checkVehicle() {
    // ...
}

Note: Same feature can achieve  since Java 8 with repeating annotations as described above.

[Solved] java.lang.ClassCastException: org.apache.logging.slf4j.SLF4JLoggerContext cannot be cast to org.apache.logging.log4j.core.LoggerContext


ClassCastException throws in code has attempted to cast an object to a subclass of which it is not an instance.

  • ClassCastException(): Constructs a ClassCastException with no detail message.
  • ClassCastException( String s): Constructs a ClassCastException with specified detail message.

Exception Stack Trace

Caused by: java.lang.ClassCastException: org.apache.logging.slf4j.SLF4JLoggerContext cannot be cast to org.apache.logging.log4j.core.LoggerContext
    at org.apache.logging.log4j.core.LoggerContext.getContext(LoggerContext.java:190) ~[log4j-core-2.10.0.jar:2.10.0]
    at org.apache.logging.log4j.core.config.Configurator.setLevel(Configurator.java:291) ~[log4j-core-2.10.0.jar:2.10.0]
    at org.elasticsearch.common.logging.Loggers.setLevel(Loggers.java:149) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.common.logging.Loggers.setLevel(Loggers.java:144) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.index.SearchSlowLog.setLevel(SearchSlowLog.java:111) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.index.SearchSlowLog.(SearchSlowLog.java:106) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.index.IndexModule.(IndexModule.java:127) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.indices.IndicesService.createIndexService(IndicesService.java:440) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.indices.IndicesService.createIndex(IndicesService.java:413) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.cluster.metadata.MetaDataCreateIndexService$1.execute(MetaDataCreateIndexService.java:378) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.cluster.ClusterStateUpdateTask.execute(ClusterStateUpdateTask.java:45) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.cluster.service.ClusterService.executeTasks(ClusterService.java:634) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.cluster.service.ClusterService.calculateTaskOutputs(ClusterService.java:612) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.cluster.service.ClusterService.runTasks(ClusterService.java:571) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.cluster.service.ClusterService$ClusterServiceTaskBatcher.run(ClusterService.java:263) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.cluster.service.TaskBatcher.runIfNotProcessed(TaskBatcher.java:150) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.cluster.service.TaskBatcher$BatchedTask.run(TaskBatcher.java:188) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingRunnable.run(ThreadContext.java:575) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.runAndClean(PrioritizedEsThreadPoolExecutor.java:247) ~[elasticsearch-5.6.10.jar:5.6.10]
    at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.run(PrioritizedEsThreadPoolExecutor.java:210) ~[elasticsearch-5.6.10.jar:5.6.10]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) ~[na:1.8.0_151]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) ~[na:1.8.0_151]
    at java.lang.Thread.run(Unknown Source) ~[na:1.8.0_151]

Issue

This exception “org.apache.logging.slf4j.SLF4JLoggerContext cannot be cast to org.apache.logging.log4j.core.LoggerContext” occurs because project build with maven and contains spring-boot-starter-web which imports the dependency because we can’t skip with spring-boot-starter-web and need log4j.

Solutions 1

Solution to get log4j with web project is to exclude log4j-to-slf4 from class path as given below:


    
    org.springframework.boot
    spring-boot-starter-web
    
    
        org.apache.logging.log4j
        log4j-to-slf4j
    
    

Solutions 2

If you are using simple Spring boot console based application or any Spring template and interfacing with this exception.



org.springframework.boot
spring-boot-starter-log4j2



org.apache.logging.log4j
log4j-to-slf4j
2.0.2



org.apache.logging.log4j
log4j-to-slf4j;
2.0.2-sources;



org.apache.logging.log4j
log4j-slf4j-impl;
2.0.2;



org.apache.logging.log4j
log4j-slf4j-impl;
2.0.2-sources;

More Issues Solution

For more other JAVA/JDBC issues solution follow link JAVA/JDBC Issues.