Category Archives: web development

Java 8 – Some of the new features

In this post, some of the new features of JAVA 8…

package pt.joaobrito.java8;

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.Month;
import java.time.Period;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

public class Main {

    public static void main(String[] args) throws InterruptedException {
        // simple lambda example
        print("Hello Lambda", s -> s.length());

        // another lambda example
        new Thread(() -> System.out.println("Hello Runnable")).start();

        List<Person> people = new ArrayList<>(Arrays.asList(
            new Person("John Doe", LocalDate.of(1978, Month.JUNE, 14)),
            new Person("Jane Doe", LocalDate.of(1983, Month.FEBRUARY, 16)),
            new Person("Steven Smith", LocalDate.of(2008, Month.SEPTEMBER, 23)),
            new Person("Martin", LocalDate.of(2010, Month.NOVEMBER, 27)),
            new Person("Mike", LocalDate.of(2012, Month.NOVEMBER, 3)),
            new Person("Louis", LocalDate.of(2014, Month.NOVEMBER, 6)),
            new Person("Mary", LocalDate.of(2016, Month.FEBRUARY, 16))
        ));

        System.out.println("---- All people sorted by name -----");
        people.sort((p1, p2) -> p1.getName().compareTo(p2.getName()));
        people.forEach(p -> System.out.println(p.getName()));

        System.out.println("---- All people -----");
        people = new ArrayList<>(Arrays.asList(
            new Person("John Doe", LocalDate.of(1978, Month.JUNE, 14)),
            new Person("Jane Doe", LocalDate.of(1983, Month.FEBRUARY, 16)),
            new Person("Steven Smith", LocalDate.of(2008, Month.SEPTEMBER, 23)),
            new Person("Martin", LocalDate.of(2010, Month.NOVEMBER, 27)),
            new Person("Mike", LocalDate.of(2012, Month.NOVEMBER, 3)),
            new Person("Louis", LocalDate.of(2014, Month.NOVEMBER, 6)),
            new Person("Mary", LocalDate.of(2016, Month.FEBRUARY, 16))
        ));
        people.stream().map(Person::getName).forEach(System.out::println); // using method reference

        System.out.println("---- People older than 9 yrs -----");
        people
            .stream() // convert to stream
            .filter(p -> Period.between(p.getDob(), LocalDate.now()).getYears() > 9) // get only the people thaht matches the given condition
            .map(Person::getName) // get a new stream with only the names => returns Stream<String>
            .forEach(System.out::println); // iterates the entire stream and prints out each element

        System.out.println("---- Remove items from list -----");
        people.removeIf(i -> i.getAge() < 2); // remove if the given condition is true
        people.
            stream()
            .map(Person::getName)
            .sorted(Comparator.reverseOrder()) // order the list in reverse order
            .forEach(System.out::println);

        // calculate time between two dates
        LocalDate dob = LocalDate.of(1978, 6, 14);
        LocalDate now = LocalDate.now();
        Period p = Period.between(dob, now);
        System.out.println("Priod of " + p.getYears() + " years; " + p.getMonths() + " months, " + p.getDays() + " days.");

        // calculate time between two instants
        Instant start = Instant.now();
        Thread.sleep(1000);
        Instant end = Instant.now();
        System.out.println("The time is... " + Duration.between(start, end).toMillis());

        // Optional<T>
        Optional<String> opt = Optional.ofNullable("some string"); // not null value
        System.out.println(opt.orElse("or else"));
        opt.orElseThrow(UnsupportedOperationException::new);

        opt = Optional.ofNullable(null); // notice that here we pass a null value
        System.out.println(opt.orElse("or else"));
        opt.orElseThrow(UnsupportedOperationException::new);

    }

    public static void print(String s, MyLambda l) {
        System.out.println(l.getLength(s));
    }

}

@FunctionalInterface
interface MyLambda {
    int getLength(String s);
}
package pt.joaobrito.java8;

import java.time.LocalDate;
import java.time.Period;

public class Person {
    private String name;
    private LocalDate dob;

    public Person(String name, LocalDate dob) {
        this.name = name;
        this.dob = dob;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public LocalDate getDob() {
        return dob;
    }

    public void setDob(LocalDate dob) {
        this.dob = dob;
    }
    
    public int getAge(){
        return Period.between(dob, LocalDate.now()).getYears();
    }
}

 

…and here are the results from running the file above

------------------------------------------------------------------------
Building Java8 0.0.1-SNAPSHOT
------------------------------------------------------------------------

--- exec-maven-plugin:1.2.1:exec (default-cli) @ Java8 ---
12
Hello Runnable
---- All people sorted by name -----
Jane Doe
John Doe
Louis
Martin
Mary
Mike
Steven Smith
---- All people -----
John Doe
Jane Doe
Steven Smith
Martin
Mike
Louis
Mary
---- People older than 9 yrs -----
John Doe
Jane Doe
---- Remove items from list -----
Steven Smith
Mike
Mary
Martin
Louis
John Doe
Jane Doe
Priod of 39 years; 9 months, 9 days.
The time is... 1014
some string
or else
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.Optional.orElseThrow(Optional.java:290)
	at pt.joaobrito.java8.Main.main(Main.java:83)
------------------------------------------------------------------------
BUILD FAILURE
------------------------------------------------------------------------
Total time: 1.649 s
Finished at: 2018-03-23T00:07:33+00:00
Final Memory: 8M/309M
------------------------------------------------------------------------

Note that the build fails because we pass null to the Optional and we have a condition to throw an exception if null is passed to it (this is the reason why this line is the last statement of this example).

Thank you! 🙂

 

Working with nested Maps in JAVA

In this post I will show you a simple and easy way of working with JAVA Maps, more precisely, how to add an element (a.k.a value) to a multi nested maps:

public void addElementToMap(Map<Long, Map<String, Map<Short, List<SomeDto>>>> map, SomeDto dto) {
	
	// get the first inner map
	Map<String, Map<Short, List<SomeDto>>> someMap = map.get(dto.gePrimaryKey());
	
	if(someMap == null){
		someMap = new HashMap<>();
		map.put(dto.gePrimaryKey(), someMap);
	}
	
	
	// get the second inner map
	Map<Short, List<SomeDto>> otherMap = someMap.get(dto.getSomeId());
	
	if(otherMap == null){
		otherMap = new HashMap<>();
		someMap.put(dto.getSomeId(), otherMap);
	}
	
	
	// get the inner list
	List<SomeDto> someList = otherMap.get(dto.getOtherId());
	
	if(someList == null){
		someList = new ArrayList<>();
		otherMap.put(dto.getOtherId()), someList);
	}
	
	// add dto to the list
	someList.add(dto);
}

That’s it. Simple, isn’t it? 😉

Source code: github

Decoupling event producers and event consumers in Java EE 6 using CDI and JMS

In this post I will show you how to decouple event producer from the event consumers (aka async events).

  1. you must configure your application server (here the glassfish settings):
  2. call the EJB method sendEvent() to send the event (from a servlet or from a web page):
    @LocalBean
    @Stateless
    public class MyEJB {
    
    	@Inject
    	@InForeground
    	private Event<BaseEvent> event;
    
    	/**
    	 * fires the @InForeground event
    	 *
    	 * @throws InterruptedException
    	 */
    	public void sendEvent() throws InterruptedException {
    		event.fire(new MyEvent("Hello world event", new Date()));
    		Thread.sleep(5000);
    	}
    }
  3. the EJB fires the event anotaded with @InForeground qualifier.
  4. An observer method handle the event and send it to the JMS Queue with the help of a message producer:
    @Stateless
    public class BackgroundEventSender implements BackgroundEventSenderItf {
    
    	@Resource(mappedName = "myConnectionFactory") // the JNDI name for this connection factory
    	private ConnectionFactory connectionFactory;
    
    	@Resource(mappedName = "myQueue") // JNDI name for this queue
    	private Queue backgroundEventQueue;
    
    	private Connection connection;
    	private Session session;
    	private MessageProducer producer;
    
    	@PostConstruct
    	public void init() {
    		try {
    			connection = connectionFactory.createConnection();
    			session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
    			producer = session.createProducer(backgroundEventQueue);
    		} catch (JMSException ex) {
    			throw new RuntimeException(ex.getMessage(), ex);
    		}
    	}
    
    	@PreDestroy
    	public void destroy() {
    		try {
    			if (connection != null) {
    				connection.close();
    			}
    		} catch (Exception ex) {
    			// todo: handle the exception
    		}
    
    	}
    
    	/**
    	 * sends the foreground event to the queue with the help of the producer object
    	 *
    	 * @param event
    	 */
    	@Override
    	public void event(@Observes @InForeground BaseEvent event) {
    		try {
    			ObjectMessage msg = session.createObjectMessage();
    			msg.setObject(event);
    			producer.send(msg);
    		} catch (JMSException ex) {
    			throw new RuntimeException(ex.getMessage(), ex);
    		}
    
    	}
    
    }
  5. Now, in another (background) thread, the onMessage method handle the message and fires a new event (which wraps the received event) now annotated with @InBackground qualifier:
    @MessageDriven(mappedName = "myQueue", activationConfig = {
    	@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
    	@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
    })
    public class BackgroundEventDispatcher implements MessageListener {
    
    	public BackgroundEventDispatcher() {
    	}
    
    	@Inject
    	@InBackground
    	private Event<BaseEvent> event;
    
    	/**
    	 * dispatches the message received from the queue and fires a new event (now with the @InBackground qualifier)
    	 *
    	 * @param message
    	 */
    	public void onMessage(Message message) {
    		if (!(message instanceof ObjectMessage)) {
    			throw new RuntimeException("Invalid message type received");
    		}
    		ObjectMessage msg = (ObjectMessage) message;
    		try {
    			Serializable eventObject = msg.getObject();
    			if (!(eventObject instanceof BaseEvent)) {
    				throw new RuntimeException("Unknown event type received");
    			}
    			BaseEvent evt = (BaseEvent) eventObject;
    			this.event.fire(evt);
    
    		} catch (JMSException ex) {
    			throw new RuntimeException(ex.getMessage(), ex);
    		}
    	}
    }
  6. And finally, if you have a method that consumes events annotated with @InBackground qualifier, then you receive the event and process it accordingly to your business needs.
    @Stateless
    public class EventConsumer implements EventConsumerItf {
    
    	/**
    	 * consumes the event sent by the JMS queue
    	 *
    	 * @param event
    	 */
    	@Override
    	public void afterMyEvent(@Observes @InBackground MyEvent event) {
    		System.out.println("Event message: " + event.getData());
    		System.out.println("Event time: " + new SimpleDateFormat("yyyy.MM.dd @ HH:mm:ss").format(event.getEventTime()));
    	}
    
    }

The event object it’s just a POJO like this one:

public class MyEvent extends BaseEvent {

	private String data;

	private Date eventTime;

	public String getData() {
		return data;
	}

	public MyEvent(String data, Date eventTime) {
		this.data = data;
		this.eventTime = eventTime;
	}

	public void setData(String data) {
		this.data = data;
	}

	public Date getEventTime() {
		return eventTime;
	}

	public void setEventTime(Date eventTime) {
		this.eventTime = eventTime;
	}
}

You can get the full code from github. Thank you!

Feel free to comment.

Date Range Validation with Annotations in JAVA

In this post I will show you how to validate date ranges with JAVA annotation.

simple date range validation
simple date range validation

XHTML page:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
	  xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
		<h1>Simple Date Range Validation with Annotation</h1>
		<h:form>
			<h:messages style="color: red" />
			<h:outputText value="First Date" /><br />
			<h:inputText value="#{simpleDateRangeController.dto.startDate}" >
				<f:convertDateTime pattern="yyyy-MM-dd" />
			</h:inputText><br />
			<h:outputText value="Second Date" /><br />
			<h:inputText value="#{simpleDateRangeController.dto.endDate}" >
				<f:convertDateTime pattern="yyyy-MM-dd" />
			</h:inputText><br />
			<h:commandButton value="submit" action="#{simpleDateRangeController.action()}" />
			<br />
			<h:commandLink value="next" action="multipledaterange" immediate="true"/>
		</h:form>
    </h:body>
</html>

This is a simple JSF page with two date inputs and a submit button. When we press the button a the validation process will start via the backing bean that call a super class method.

Backing Bean:

@Named
@RequestScoped
public class SimpleDateRangeController extends AbstractController {

	private SimpleDateRangeDto dto;

	@PostConstruct
	public void init() {
		dto = new SimpleDateRangeDto();
	}

	public SimpleDateRangeController() {
	}

	public void action() {
		super.validate(dto);
	}

	// getters and setters

}
</pre> 

Note that in line 3 we have the super class named: AbstractController. In line 16, in the action method, we call a validate method and we pass as a parameter the dto wich has the data itself.

Abstract Controller

public class AbstractController implements Serializable {

	protected <T extends DateRangeValidation> void validate(T dto) {
		dto.validate();
	}
}

In this abstract class we simple call the validate() method in the received DTO.

Data Transfer Object(DTO):

@ValidDateRange(endDesc = "end date", startDesc = "start date")
public class SimpleDateRangeDto extends DateRangeValidation {

	private Date startDate;
	private Date endDate;

	// getters and setters

}

Here is the point where we annotate at the class-level with our special annotation. We simple use the annotation with 2 parameters. This parameters are optional and it’s purpose is only to personalize the error message. In case that your date fields are different from those in this example you must provide the annotation with more parameters, as you will see in the next class.

Annotation:

@Documented
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = {DateIntervalValidator.class})
public @interface ValidDateRange {

	@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE})
	@Retention(RUNTIME)
	@Documented
	public @interface List {
		ValidDateRange[] value();
	}

	String message() default "{endDesc} must be after {startDesc}.";
	String start() default "startDate";
	String end() default "endDate";
	String startDesc() default "start date";
	String endDesc() default "end date";
	Class<?>[] groups() default {};
	Class<? extends Payload>[] payload() default {};

	class DateIntervalValidator implements ConstraintValidator<ValidDateRange, Object> {

		private static final String GET = "get";

		private String startDate;
		private String endDate;

		@Override
		public void initialize(ValidDateRange constraintAnnotation) {
			startDate = constraintAnnotation.start();
			endDate = constraintAnnotation.end();
		}

		@Override
		public boolean isValid(Object value, ConstraintValidatorContext context) {
			Class<?> clazz = value.getClass();

			try {
				Method m1 = clazz.getMethod(getMethodByField(startDate), (Class<?>[]) null);
				Method m2 = clazz.getMethod(getMethodByField(endDate), (Class<?>[]) null);

				final Date d1 = (Date) m1.invoke(value, (Object[]) null);
				final Date d2 = (Date) m2.invoke(value, (Object[]) null);

				if (d2 == null) {
					return true;
				}
				if (d1 != null && d1.after(d2)) {
					return false;
				}

			} catch (Exception e) {
			}
			return true;
		}

		private String getMethodByField(String field) {
			StringBuilder sb = new StringBuilder(GET)
					.append(field.substring(0, 1).toUpperCase())
					.append(field.substring(1));
			return sb.toString();
		}
	}
}

Here is where the magic happens. I will not discuss how annotations work, but I will cover the essential part: the constraint validation. The inner class DateIntervalValidator is responsible for the validation of the date fields with the help of reflection. We get the get methods of the two date fields and then we verify if endDate is after startDate. If that condition is false, we return false, otherwise we return true.
The message is required if you want personalize your message.
The start is required if your first date field is different from startDate. It indicates the name of the first field.
The end is required if your end date field is different from endDate. It indicates the name of the second date field.
The purpose the startDesc and endDesc is to use as a placeholder in the message parameter.

Validator:

public abstract class DateRangeValidation implements Serializable {

	private static final long serialVersionUID = 7083856980011157895L;

	public void validate() {
		ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
		Validator validator = validatorFactory.getValidator();
		Set<ConstraintViolation<DateRangeValidation>> result = validator.validate(this);

		if (!result.isEmpty()) {
			Iterator<ConstraintViolation<DateRangeValidation>> it = result.iterator();
			while (it.hasNext()) {
				String mesg = it.next().getMessage();
				FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, mesg, mesg));
			}
			FacesContext.getCurrentInstance().validationFailed();
		}
	}
}

This class is the trigger of all the validation process. When in the DTO we call the validate method, is this method we are calling, because this class is the superclass of the DTO. It calls the annotation and validates the fields. If there are any erros it will collect them in a set, here called as result. Then we iterate all over the set and add the error messages to faces context.

The next few files demonstrate the same logic applied to 2 or more groups of date validations.


multiple date range validation
multiple date range validation

XHTML:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
	  xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
		<h1>Multiple Date Range Validation with Annotations</h1>
		<h:form>
			<h:messages style="color: red" />
			<h:outputText value="First Date" /><br />
			<h:inputText value="#{multipleDateRangeController.dto.date1}" >
				<f:convertDateTime pattern="yyyy-MM-dd" />
			</h:inputText><br />
			<h:outputText value="Second Date" /><br />
			<h:inputText value="#{multipleDateRangeController.dto.date2}" >
				<f:convertDateTime pattern="yyyy-MM-dd" />
			</h:inputText><br />
			<h:outputText value="Third Date" /><br />
			<h:inputText value="#{multipleDateRangeController.dto.date3}" >
				<f:convertDateTime pattern="yyyy-MM-dd" />
			</h:inputText><br />
			<h:outputText value="Fourth Date" /><br />
			<h:inputText value="#{multipleDateRangeController.dto.date4}" >
				<f:convertDateTime pattern="yyyy-MM-dd" />
			</h:inputText><br />
			<h:commandButton value="submit" action="#{multipleDateRangeController.action()}" /><br />
			<h:commandLink value="back" action="simpledaterange" immediate="true" />
		</h:form>
    </h:body>
</html>

Backing Bean:

@Named
@RequestScoped
public class MultipleDateRangeController extends AbstractController {

	private MultipleDateRangeDto dto;

	@PostConstruct
	public void init() {
		dto = new MultipleDateRangeDto();
	}

	public MultipleDateRangeController() {
	}

	public void action() {
		super.validate(dto);
	}

	// getters and setters

}

DTO:

@ValidDateRange.List({
	@ValidDateRange(start = "date1", end = "date2", message = "{end} must be after {start}"),
	@ValidDateRange(start = "date3", end = "date4", message = "{end} must be after {start}")
})
public class MultipleDateRangeDto extends DateRangeValidation {

	private Date date1;
	private Date date2;
	private Date date3;
	private Date date4;

	// getters and setters

}

Plase feel free to comment or to suggest new features.
You can read more about this topic here
Download source code.
Thanks.

JAVA EE – CDI Interceptor Example

In this post I will explain you one simple way of using interceptors in Java EE.

We have a simple java project that only displays a name wich is setted in the Controller class by the init method. But as you will see next, the final result it’s not the name that is setted by the controler, because we have an interceptor that changes the name behind the scenes.

The index page index.xhtm makes a server request to display the name. But that request is going to be intercepted by our interceptor MyInterceptor.java. Then who makes the request to the controller is the interceptor and if the response is of the type String it changes it to another string. When the page renders it will show not the response from the controller but the object that our interceptor returns to it.

And that’s it. Even without the final user knows nothing about it, the response has been manipulated by our interceptor.

  • Project Scheme
interceptor_project
interceptor_project

 

  • index.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        #{controller.name}
    </h:body>
</html>

 

  • Controller.java
package pt.joaobrito.controller;

import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import pt.joaobrito.annotation.LogToConsoleAndModifyResult;

@Named
@RequestScoped
@LogToConsoleAndModifyResult
public class Controller {

	private String name;

	public Controller() {
	}

	@PostConstruct
	public void init() {
		this.name = "John Doe";
	}

	public String getName() {
		return name;
	}

}

Note that in line 10 we have a special annotation. This marks this bean to be intercepted, as you will see next.  The code in the 20th line, just sets the variable name to John Doe.

  • LogToConsoleAndModifyResult.java
package pt.joaobrito.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.interceptor.InterceptorBinding;

@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@InterceptorBinding
public @interface LogToConsoleAndModifyResult {

}

This is a simple annotation class (out of the scope of this post, for now). The important thing here is the @InterceptorBinding annotation.

  • MyInterceptor.java
package pt.joaobrito.interceptor;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import pt.joaobrito.annotation.LogToConsoleAndModifyResult;

@Interceptor
@LogToConsoleAndModifyResult
public class MyInterceptor {

	@AroundInvoke
	public Object interceptAndLog(InvocationContext ic) throws Exception {
		Logger logger = getLogger(ic);
		// this is executed before the method being intercepted
		logger.log(Level.INFO, "before the method being intercepted...");

		// the object returned after the execution of the intercepted method
		Object result = ic.proceed();

		// if the intercepted method returns a String, we can modify it
		if (result instanceof String) {
			// this is executed real result of the intercepted method
			logger.log(Level.INFO, "the real result of the intercepted method is: " + (String) result);

			// now we change the result without the final user knows that the method is being intercepted
			result = "Jane Doe";
		}

		try {
			// we return the modified object, or the original (if it was not a string)
			return result;
		} finally {
			// this is executed after the method being intercepted
			logger.log(Level.INFO, "after the method being intercepted... thne name is: " + (String) result);
		}
	}

	private Logger getLogger(InvocationContext ctx) {
		return Logger.getLogger(ctx.getMethod().getClass().toString());
	}
}

In the MyInterceptor class we have 3 important annotations:

@Interceptor  (line 10),
@LogToConsoleAndModifyResult  (line 11) and the
@AroundInvoke  (line 14).

The first one makes this bean an interceptor. The second, marks this interceptor to intercept all methods in classes  annotated with the the same annotation. The last one, marks the method that is going to manipulate all the data.

Note that this method must returns an Object and as a parameter it takes the invocation context.

First we have a logger that prints out to the console a message before the interception. Then with the help of the invocation context, it lets the original method to proceed and keeps the result. Then it prints again to the console the real name returned by the controller (John Doe). After this, it changes the return value to Jane Doe, that is exactly what is going to be displayed in the page as the final result.

  • beans.xml
<beans>
	<interceptors>
		<class>pt.joaobrito.interceptor.MyInterceptor</class>
	</interceptors>
</beans>

Finally, in order to use interceptors we must register them in the beans.xml file (line 3). Another possibility is to annotate the controller with @Interceptors({MyInterceptor.class}) but this approach is not recommended.

  •  The Log

the log messages

Here are the three messages sent to the console.

  • The result page

web page

As you can see here the displayed name isn’t John Doe, as you might expect, but the modified result: Jane Doe.

—
Source code

Feel free to comment.

Logger CDI Injection

In this post I will show you how to inject an instance of Logger class using CDI (Context Dependency Injection) and SLF4J (Simple Logging Facade for Java).

To keep it simple, we only have a xhtml page (index), a managed bean (Controller.java) and the producer (LoggerProducer.java). The project configuration is as follows:

project
project

 

As we are using JSF with facelets, the index page looks like:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head>
        <title>CDI Producer</title>
    </h:head>
    <h:body>
        <h2>The name is: #{controller.name}</h2>
    </h:body>
</html>

In this file we simply display the name that is setted in the controller (line 10).

 

package pt.joaobrito.controller;

import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.slf4j.Logger;

@Named
@RequestScoped
public class Controller {

	@Inject
	private Logger logger;

	private String name;

	public Controller() {
	}

	@PostConstruct
	public void init() {
		logger.info("before setting the name: name = " + name);
		this.name = "John Doe";
		logger.info("the name was setted to: name = " + name);
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

In the controller we inject (@Inject) an instance of the Logger class and print to the console the name before and after the name is setted (lines 23 and 25). CDI knows which Logger to inject because we have a class that works as a factory of Loggers (LoggerProducer) with some special annotations.

 

package pt.joaobrito.producer;

import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Dependent
public class LoggerProducer {

	@Produces
	public Logger newLoggerInstance(InjectionPoint ip) {
		return LoggerFactory.getLogger(ip.getMember().getClass());
	}
}

In the LoggerProducer class we have an annotation (@Produces) in a method that returns a Logger instance. This is enough to CDI inject a Logger when needed. Notice that in line 13 we pass as a parameter the injection point (ip) in order to get the class where the logger is being injected (in this specific case ‘Controller.class’). This is only necessary beacuse the getLogger method needs it.

Finally, here are the results (the log and the web page):

log

log

As you can see here, we have two lines displaying the information that we expected: first the name is null and after the set of the variable name, name = John Doe.

the result page
the result page

 

That’s it. It’s just that simple!

Conclusion

First we create a factory of loggers, then we inject them whenever we need them:
@Produces to indicate CDI what we are producing and
@Inject to inject the instance ready to use.

Notice that this methodology works with other types rather than Logger. You may inject whatever you want by simply following the above technic.

Feel free to comment.

Source code