Java One 2017 o que vem por ai

 

O JavaOne é um dos maiores e mais importantes evento Java do mundo, ele acontece anualmente no segundo semestre na cidade de São Francisco, Califórnia. É nele que acontece o lançamento das maiores novidades da linguagem e/ou da plataforma. O evento conta com diversas palestras em diversos hotéis na região, o objetivo desse post é fazer sugestão de palestras que você não deveria perder.

 

Grandes Lançamentos:

Estar atento das novidades da plataforma é sempre muito bom para os curiosos e os profissionais. Esse ano em especial, possivelmente, haverá três grandes lançamentos:

Estar atento a essas palestras e ficar por dentro dessas novidades valerá a pena.

JNoSQL

duke-diana.png

O JNoSQL é um dos recentes projetos que eu venho trabalhando nos últimos meses. O JNoSQL é um framework cujo o objetivo é facilitar a integração os bancos não relacionais e o Java EE. A ideia é que ele tenha uma API comum entre esses bancos, porém, levando considerações extenções para comportamentos específicos dos bancos de dados não relacionais.

  • JNoSQL: The Definitive Solution for Java and NoSQL Database [CON4954]
  • Choosing a NoSQL API and Database to Avoid Tombstones and Dragons in Game On! [CON1756]
  • Building a Recommendation Engine with Java EE [CON7608]

 

Palestras dos Outros Brazucas

Assistir palestras dos conterrâneos é sempre muito legal:

  • Build, Test, and Deliver Code Faster with Containers [CON4560]
  • Trust Your Pipeline: Automatically Testing an End-to-End Java Application [CON6121]
  • Secrets of Rock Star Developers (and How to Become One!) [CON7615]
  • Everything You Ever Wanted to Know About Java and Didn’t Know Whom to Ask [CON7613]
  • “Protecting Microservices: Best Practices and Strategies”
  • Java EE 8: Hands-on with the New Features
  • Java Test Automation for REST, Web and Mobile
  • What’s New in Java EE 8? An Overview
  • Trust your Pipeline: Automatically Testing an End-to-end Java Application
  • The Hidden Secret of Java Open Source Projects [CON3754]
  • 5 Pillars of a Successful Java Web Application [CON3755]
  • 12 Factors for Cloud Success [CON5598]
  • Java Test Automation for REST, Web, and Mobile [CON6070]
  • Microservices Data Patterns: CQRS and Event Sourcing [CON7610]
  • Build, Test, and Deliver Code Faster with Containers [CON4560]
  • Trust Your Pipeline: Automatically Testing an End-to-End Java Application [CON6121]
  • Secrets of Rock Star Developers (and How to Become One!) [CON7615]
  • Everything You Ever Wanted to Know About Java and Didn’t Know Whom to Ask [CON7613]
  • Powerful Lessons from Top Java EE Experts [CON7624]

Hackergarten:

Se seu negócio é programar, que tal pôr a mão na massa? O grande barato do é Hackergarten esse! Essa interação é sensacional! Você aprende pondo a mão na prática, ganha networking, e fala diretamente com o responsável pela tecnologia. Pessoalmente, essa é a melhor parte do evento! Afinal, conseguimos falar do Java 9, Java EE, Bean Validation, JSRs, a partir do Adopt a JSR, diretamente com as pessoas que estão na frente do projeto. Isso mesmo, você pode falar diretamente com as pessoas que define a tecnologia que o mundo todo utiliza.

Confira a programação:

https://docs.google.com/spreadsheets/d/1SEVEmYA2r25gtl_w47nFPw-i_s1DPAyHthfeEi1QgLk/edit#gid=0

Networking

 

Sim, conhecer pessoas é sempre muito legal, você pode conhecer seu próximo colega de trabalho, sócio, funcionário dentre outros.  Sem falar que todo dia tem uma festa em um local diferente.

 

Anúncios

Lançamento do Moneta 1.1

 

A implementação de referência da JSR 354, money-api. Lança uma nova versão. O moneta, o nome da implementação de referência do money-api, vem algumas novidades além da correção de mais de vinte bugs. Dentre eles podemos destacar:

Além das correções foram adicionados novos métodos construtores para as implementações do MonetaryAmount.

  • zero(CurrencyUnit currency) – retorna um valor monetário igual a zero com a moeda informada.
  • ofMinor(CurrencyUnit currency, long amountMinor) – retorna o valor monetário a partir da moeda informada e do valor em centavos, por exemplo, o ofMinor(USD, 1234) retorna uma instância USD 12,34.
  • ofMinor(CurrencyUnit currency, long amountMinor, int factionDigits) – retorna o valor monetário a partir da moeda informada e do valor em centavos, por exemplo, o ofMinor(USD, 1234, 2) retorna uma instância USD 12,34. Diferente do método de criação anterior, utiliza o número de dígitos informado ao invés do número de dígitos da moeda.

 

MonetaryAmount money = Money.zero(dollar);
MonetaryAmount oneDollar = Money.ofMinor(dollar, 12_34);

MonetaryAmount money = FastMoney.zero(dollar);
MonetaryAmount oneDollar = FastMoney.ofMinor(dollar, 12_34);

MonetaryAmount money = RoundedMoney.zero(dollar);
MonetaryAmount oneDollar = RoundedMoney.ofMinor(dollar, 12_34);

Outro ponto é que a classe MonetaryUtil foi depreciada, o maior motivo é a duplicidade do nome, afinal, o termo util cabe qualquer coisa. Ao invés disso, foram criadas duas classes utilitárias:
A classe MonetaryOperators : utilitária da interface MonetaryOperator, nele contém diversas implementações interessantes que fazem a vida do desenvolvedor mais fácil, como por exemplo,

MonetaryAmount amount = ////USD 12.23
amount.with(MonetaryOperators.majorPart());//USD 12
amount.with(MonetaryOperators.minorPart());//USD 0.23
amount.with(MonetaryOperators.percent(10));//USD 1.223

MonetaryQueries: utilitária da interface MonetaryQuery, nele contém diversas implementações interessantes e que facilita a extração de informações do montante financeiro.

MonetaryAmount amount = //USD 12.32
amount.query(MonetaryQueries.convertMinorPart());//1232
amount.query(MonetaryQueries.extractMajorPart());//12
amount.query(MonetaryQueries.extractMinorPart());//32

Outra novidade está relacionado a cotação, agora é possível realizar buscas de cotação no IMF.

CurrencyUnit dollar = Monetary.getCurrency("USD");
CurrencyUnit real = Monetary.getCurrency("BRL");

MonetaryAmount money = FastMoney.of(10, dollar);
MonetaryAmount money2 = FastMoney.of(10, real);

LocalDate localDate = Year.of(2009).atMonth(Month.JANUARY).atDay(9);
ExchangeRateProvider provider = MonetaryConversions.getExchangeRateProvider(ExchangeRateType.IMF_HIST);
ConversionQuery query = ConversionQueryBuilder.of().setTermCurrency(dollar).set(localDate).build();

CurrencyConversion currencyConversion = provider.getCurrencyConversion(query);
MonetaryAmount result = currencyConversion.apply(money2);
MonetaryAmount monetaryAmount = money.add(result);

Também foi adicionado um novo recurso para formatar o MonetaryAmount.

MonetaryAmountFormat defaultFormat = MonetaryAmountDecimalFormatBuilder.newInstance().build();
MonetaryAmountFormat patternFormat = MonetaryAmountDecimalFormatBuilder.of("¤ ###,###.00").build();
MonetaryAmountFormat localeFormat = MonetaryAmountDecimalFormatBuilder.of(Locale.US).build();

CurrencyUnit currency = Monetary.getCurrency("BRL");
MonetaryAmount money = Money.of(12, currency);
String format = defaultFormat.format(money);//$12.00
MonetaryAmount moneyParsed = Money.parse(format, defaultFormat);//or using defafult.parse(format);

Com isso foi discutido sobre a nova versão do moneta, a versão 1.1. Nessa versão além de ter realizado diversas correções, foram adicionados novos recursos para formatação, cotação e deixar API cada vez mais fácil. Com essa versão finalizada, os esforços já foram iniciados para a próxima versão que o maior benefício é a modularização do moneta.

Novidades do CDI 2.0

cdi_herologo

A especificação de injeção de contexto e dependência, o CDI, certamente foi umas das grandes novidades que surgiram com o Java EE 6. Ele funciona basicamente como uma “cola” para o Java EE, realizando integrações entre os seus beans, recurso, dentro do servidor de aplicação. Nessa nova versão, o CDI 2.0, que está previsto para junho de 2016 teremos algumas novidades. E esse post tem o objetivo de dar uma visão delas. Vale lembrar como ainda se tem tempo para o lançamento muitas dessas novidades ainda estão sendo discutidas e codificadas.

  • A API foi subdividida, agora é possível utilizar uma pequena parte dela, ao invés, de todo o contexto. Assim, será possível rodar em dispositivos que tem menos memória e processamento, por exemplo, a IoT, plataformas embarcadas e até mesmo no Android. Sim, a ideia é realizar um CDI lite, assim irão o básico de injeção de dependência (definição de bean, @Inject, qualificadores, produtores, evento) até todos os recurso.
  • Melhorias nos eventos: definir ordem para os eventos além de poder lançar eventos de forma assíncrona.
  • O uso de programação orientada a aspecto para melhorar os interceptors e decoradores.

Para exemplificar o uso de CDI, será imaginado um simples aplicativo, venda de livros, utilizando apenas o Java SE. O primeiro passo será a criação de um projeto maven e será adicionado a dependência do CDI 2.0, ainda na fase de desenvolvimento, com a sua implementação de referência, o weld.

    <dependencies> 
        <dependency> 
            <groupId>org.jboss.weld.se</groupId> 
            <artifactId>weld-se-core</artifactId> 
            <version>3.0.0.Alpha15</version> 
        </dependency> 
    </dependencies>

Adicionado a dependência, o próximo passo é container do CDI, uma característica interessante é que ele implementa o AutoCloseable, recurso oriundo do Java 7 que permite que a JVM feche o recurso tão logo sai do bloco try. Assim ao executar o código abaixo é possível ver no log o Weld SE container STATIC_INSTANCE shut down.

import org.jboss.weld.environment.se.Weld; 
import javax.enterprise.inject.spi.CDI; 

public class App { 
    public static void main(String[] args) { 

        try (CDI<Object> container = new Weld().initialize()) { 

        } 
    } 
} 

É possível fazer as mesmas coisas como no Java EE, assim é possível realizar injeção de dependência apenas com a anotação @Inject.

public class PaymentMethod { 

    public void payment() { 
        System.out.println("Doing payment"); 
    } 
} 

public class Checkout { 

    @Inject 
    private PaymentMethod paymentMethod; 

    public void checkout() { 
        System.out.println("doing checkout "); 
        paymentMethod.payment(); 
    } 
} 

Retornando a classe App, é possível iniciar uma classe a partir do container do CDI, nesse exemplo será a classe Checkout. O CDI será responsável por iniciar a classe e injetar todas as suas dependências.

public class App { 
    public static void main(String[] args) { 

        try (CDI<Object> container = new Weld().initialize()) { 
            Checkout checkout = container.select(Checkout.class).get(); 
            checkout.checkout(); 
        } 
    } 
} 

Também é possível ensinar o CDI a criar uma instância utilizando o método produtor, por exemplo:

public class User implements Serializable {

private String name;

private String email;

public User(String name, String email) {
this.name = name;
this.email = email;
}

String getName() {
return name;
}

String getEmail() {
return email;
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder("User{");
sb.append("name='").append(name).append('\'');
sb.append(", email='").append(email).append('\'');
sb.append('}');
return sb.toString();
}
}

public class UserProducer {

@Produces
public User getUser() {
return new User("Otavio", "otaviojava@domain.com");
}
}

Nesse exemplo, a classe User não possui um construtor default, assim o CDI não sabe como instanciar, assim foi utilizado o @Produces dentro da classe UserProducer para ensinar o CDI como instanciar a classe usuário. Assim é possível injetá-lo, por exemplo, dentro da classe Checkout:

public class Checkout {

@Inject
private PaymentMethod paymentMethod;
@Inject
private User user;

public void checkout() {
System.out.println("doing checkout: " + user);
paymentMethod.payment();
}
}

O outro recurso que também estará disponível para SE são os qualificadores. Imagine que agora será possível ter dois métodos de pagamento:

  • Cartão de crédito
  • Dinheiro

Assim o método de pagamento passará a ser uma interface com duas implementações. Umas das maneiras para ensinar qual implementação o CDI utilizará seria a partir dos qualificadores.

public enum PaymentType {
CREDIT_CARD, CASH
}

@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Payment {
PaymentType value();
}

public interface PaymentMethod {

void payment();
}

@Payment(PaymentType.CREDIT_CARD)
public class CreditCard implements PaymentMethod {
@Override
public void payment() {
System.out.println("Payment with credit card");
}
}

@Payment(PaymentType.CASH)
@Default
public class Cash implements PaymentMethod {
@Override
public void payment() {
System.out.println("Payment with cash");
}
}

Nesse exemplo, foi criado a anotação Payment que possui um atributo, o enum PaymentType, que define os tipos de pagamento. Na implementação Cash, além do qualificador ele possui a anotação @Default, quer dizer que caso não seja definido nenhuma qualificação o CDI o injetará como padrão.

@Inject
@Payment(PaymentType.CREDIT_CARD)
private PaymentMethod paymentMethod;

Será injetado a implementação de cartão de crédito.

@Inject
@Payment(PaymentType.CASH)
private PaymentMethod paymentMethod;

@Inject
private PaymentMethod paymentMethod;

Será injetado a implementação de pagamento em dinheiro.

Uma outra possibilidade dos qualificadores é definir qual instância será utilizada em tempo de execução, basta utilizar Instance com selector.

public class Checkout {

@Inject
@Any
private Instance payments;
@Inject
private User user;

public void checkout(PaymentType type) {
System.out.println("doing checkout: " + user);
PaymentMethod paymentMethod = payments.select(new PaymentSelector(type)).get();
paymentMethod.payment();
}
}

public class PaymentSelector extends AnnotationLiteral implements Payment {

private final PaymentType type;

PaymentSelector(PaymentType type) {
this.type = type;
}

@Override
public PaymentType value() {
return type;
}
}

Definido a forma de pagamento, o próximo passo será o envio de e-mail e entregar o livro. Assim, se pode trabalhar com eventos.

public class SendEmail {

public void sendEmail(@Observes User user) {
System.out.println("Sending email to user: " + user);
}
}

public class DeliveryBook {

public void delivery(@Observes User user) {
System.out.println("Delivering a book to: " + user);
}
}

public class Checkout {

@Inject
@Any
private Instance payments;
@Inject
private User user;
@Inject
private Event userEvent;

public void checkout(PaymentType type) {
System.out.println("doing checkout: " + user);
PaymentMethod paymentMethod = payments.select(new PaymentSelector(type)).get();
paymentMethod.payment();
userEvent.fire(user);
}
}

Um recurso possível agora no 2.0 é definir a ordem em que os eventos serão chamados.

public class DeliveryBook {

public void delivery(@Observes @Priority(Interceptor.Priority.APPLICATION+2) User user) {
System.out.println("Delivering a book to: " + user);
}
}

public class SendEmail {

public void sendEmail(@Observes @Priority(Interceptor.Priority.APPLICATION+1) User user) {
System.out.println("Sending email to user: " + user);
}
}

Outra possibilidade é realizar a chamada de forma assíncrona, para isso basta trocar a nos observadores para ObservesAsync e chamar o método do evento.

public class SendEmail {

public void sendEmail(@ObservesAsync User user) {
System.out.println("Sending email to user: " + user);
}
}

public class DeliveryBook {

public void delivery(@ObservesAsync User user) {
System.out.println("Delivering a book to: " + user);
}
}

public class Checkout {

@Inject
@Any
private Instance payments;
@Inject
private User user;
@Inject
private Event userEvent;

public void checkout(PaymentType type) {
System.out.println("doing checkout: " + user);
PaymentMethod paymentMethod = payments.select(new PaymentSelector(type)).get();
paymentMethod.payment();
userEvent.fireAsync(user);
}
}

Com isso foram apresentados os novos recursos do CDI 2.0, vale lembrar que muitos ainda estão sendo trabalhados, assim esperem por mais novidades até o dia do lançamento.

Link para o código

Java 8: Stream API – Parte 2, conhecendo a API

17_1

Após falar sobre a motivação para usar o Stream API, o foco desse artigo será mostrar uma visão geral da API. Para exemplificar, será utilizado o mesmo modelo do artigo anterior, um time de futebol.

public class Team {
private List players;
//…
}

public class Player {

private String name;

private int gols;

private Position position;

//...
}

public enum Position {
GOALKEEPER,DEFENDER, FORWARDS
}

Mapeamento

É possível realizar o mapeamento e retornar apenas um campo desejável, por exemplo, retornar a listas de nomes dos jogadores.

public List getNames() {
return players.stream().map(Player::getName).
collect(Collectors.toList());
}

Collector vs Collectors

A interface Collector que realiza uma operação de redução mutável colocando os resultados em uma representação e a classe Collectors tem várias implementações úteis da interface.

Retornando Set
public List getPlayers() {
return players.stream().collect(Collectors.toList());
}
Retornando List
public Set getPlayers() {
return players.stream().collect(Collectors.toSet());
}
Criando o seu próprio retorno
public Queue getPlayers() {
return players.stream().collect(Collectors.toCollection(LinkedList::new));
}

Ordenação

É possível ordenar de forma natural, implementando o Comparable. Para exemplificar isso, a classe Player será modificado comparando os jogadores pelo nome.

public class Player implements Comparable {
@Override
public int compareTo(Player player) {
return name.compareTo(player.name);
}
}

Assim é possível ordenar pelo nome:

public List getPlayers() {
return players.stream().sorted()
.collect(Collectors.toList());
}

Ou:

public List getPlayers() {
return players.stream().sorted(Comparator.naturalOrder())
.collect(Collectors.toList());
}

Também é possível definir uma ordenação, para isso, basta usar o método comparing dentro do Comparator.

public List getPlayers() {
return players.stream().sorted(Comparator
.comparing(Player::getGols))
.collect(Collectors.toList());
}

Foma descendente.

public List getPlayers() {
return players.stream().sorted(Comparator
.comparing(Player::getGols).reversed())
.collect(Collectors.toList());
}

Juntar ordenações:

public List getPlayers() {
return players.stream().sorted(Comparator.comparing(Player::getName)
.thenComparing(Comparator.comparing(Player::getGols)))
.collect(Collectors.toList());
}

Filtragem.

Já discutido no primeiro post, vale adicionar que é possível, assim como as ordenações, realizar mais de uma condição. É possível combinar utilizando os operadores or ou and, além de negar o predicate usando o negate. Para o exemplo, serão listados todos os atacantes que fizeram mais de 3 gols.

public List getGoodFowarder() {
Predicate isFowarder = Player::isFowarder;
Predicate hasMoreThanThreeGolds = p -> p.getGols() >3;
return players.stream().filter(isFowarder.and(hasMoreThanThreeGolds)).collect(Collectors.toList());
}

public List getNotFowarder() {
Predicate isFowarder = Player::isFowarder;
return players.stream().filter(isFowarder.negate()).collect(Collectors.toList());
}

Caso se queria limitar o número de elementos na lista, pular elementos e também retornar o primeiro ou algum resultado existe os métodos limit, skip, findFirst e findAny respectivamente.

public List getThreeGoodFowarder() {
Predicate isFowarder = Player::isFowarder;
Predicate hasMoreThanThreeGolds = p -> p.getGols() >3;
return players.stream().filter(isFowarder.and(hasMoreThanThreeGolds)).limit(3).collect(Collectors.toList());
}

public Player getSecondGoodFowarder() {
Predicate isFowarder = Player::isFowarder;
Predicate hasMoreThanThreeGolds = p -> p.getGols() >3;
return players.stream().filter(isFowarder.and(hasMoreThanThreeGolds)).skip(1).findFirst().get();
}

public Player getAGoodFowarder() {
Predicate isFowarder = Player::isFowarder;
Predicate hasMoreThanThreeGolds = p -> p.getGols() >3;
return players.stream().filter(isFowarder.and(hasMoreThanThreeGolds)).findAny().get();
}

public List getFowarderOrDefenter() {
Predicate isFowarder = Player::isFowarder;
Predicate isDefener = Player::isDefender;
return players.stream().filter(isFowarder.or(isDefener)).limit(3).collect(Collectors.toList());
}

 

Trabalhando com dinheiro no Mundo Java EE [MONEY-API]

jobtrends

As aplicações Java EE estão ficando cada vez mais comuns no mundo do desenvolvimento do software para web utilizando Java. Esse crescimento se deu principalmente em 2009 com o lançamento do Java EE 6 e o nascimento do Contexto de injeção de independência, o CDI. Umas das grandes vantagens do uso do Java EE, é que ela é uma especificação Java, assim não existe o vendor lock-in, em outras palavras, não é necessário ficar preso em um fabricante. Outro ponto interessante é que caso não seja necessário usar todo o container do Java EE, é possível utilizar alguns recursos em um servidor simples, por exemplo, no caso é possível rodar o CDI, JSF, Bean validator, etc. em um container como o Tomcat. Outro ponto importante que vale ressaltar é que cada componente, citado anteriormente, é especificado separadamente, uma JSR, essas JSRs são regidas pelo JCP e todos podem participar, dar feedback, reportar bugs, etc. na concepção até o final dessa especificação Java.

O Java EE é certamente a plataforma mais popular para softwares no mundo corporativo, esses softwares têm diversos objetivos. O que eles normalmente tem em comum é o fato de lidar com dinheiro. O valor monetário é muito comum em diversos softwares, por exemplo, sistemas financeiros, locadoras, livraria, sistemas de recursos humanos, contabilidade etc. Porém não existia um padrão para trabalhar com dinheiro no mundo Java, por anos vários desenvolvedores usavam os tipos primitivos ou tipos oriundos do Java para resolver este problema, por exemplo, Long, Double, Integer, String, etc. Utilizar tipos primitivos traz diversos problemas para um software, dentre eles, falta de encapsulamento, problemas no design da API numa aplicação, quebra do SOLID, dentre outros motivos (Como falar das desvantagens do tipo primitivos para representar dinheiro não é o foco desse artigo, ficaremos apenas com esses exemplos, para mais informações existe o money-api book o link estará abaixo desse artigo). Com o intuito de solucionar esse problema existe a JSR 354, o money-api, essa especificação foi desenvolvida por diversas empresas que lidam diretamente com dinheiro, dentre elas, o Credit Suisse, uns dos maiores e mais famosos banco do mundo, e o Paypal, um dos maiores providers de pagamento do mundo.

Para tornar o artigo mais didático, será imaginado um simples exemplo de uma aplicação Java EE, um sistema de compra de livros. Nesse aplicativo, se falará de cada componente do Java EE separadamente. Se utilizará a versão atual do Java EE, JavaEE 7. O foco desse artigo não será falar sobre a API de dinheiro, apenas sua integração com o Java EE.

JPA

Para o exemplo ficar simples, o modelo livro basicamente terá três atributos:

  • Id, que será um número sequencial
  • Nome, o nome do livro
  • Valor, o valor do livro
@Entity 
public class Book implements Serializable { 

@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY) 
private Long id; 

@Column 
private String name; 

@Column 
private MonetaryAmount value; 

//getter and setter 
    
}

Um problema comum em lidar com tipos únicos, como o dinheiro, é que normalmente os bancos não tem suporte nesse tipo de informação. Uma solução para esse problema nasceu no JPA 2.1 com os converters. A criação de um converter é bastante simples, basta implementar a interface AttributeConverter.

public class MonetaryAmountConveter implements  AttributeConverter&amp;amp;lt;MonetaryAmount, BigDecimal&amp;amp;gt;{ 

    private static final CurrencyUnit CURRENCY = Monetary.getCurrency(&amp;quot;BRL&amp;quot;); 
    
    private static final MonetaryQuery&amp;amp;lt;BigDecimal&amp;amp;gt; EXTRACT_BIG_DECIMAL = (m) -&amp;amp;gt; m.getNumber() 
            .numberValue(BigDecimal.class); 
            
    @Override 
    public BigDecimal convertToDatabaseColumn(MonetaryAmount attribute) { 
       return Optional.ofNullable(attribute).orElse(FastMoney 
               .zero(CURRENCY)) 
               .query(EXTRACT_BIG_DECIMAL); 
    } 

    @Override 
    public MonetaryAmount convertToEntityAttribute(BigDecimal dbData) { 
        return Money.of(dbData, CURRENCY); 
    } 
} 

Converter do JPA que persiste apenas o valor numérico.

E definir no campo como ele será convertido, para isso existe a anotação Convert.

@Column
@Convert(converter = MonetaryAmountConveter.class)
private MonetaryAmount value;

No JPA 2.1 os converters trabalham com um campo com um campo único, assim se pode trabalhar com algumas opções:

  • Persistir apenas o número: em sistemas que trabalham apenas com uma única moeda, é possível, por exemplo, definir a moeda em uma constante, que sempre será a mesma, e assim persistir o valor numérico. Assim é possível realizar operações no próprio banco de dados, como soma, porém caso o projeto cresça e precise internacionalizar haverá um grande problema. Uma solução para contornar esse problema seria ter um tenancy para cada país/moeda.

  • Persistir o número e a moeda como String: Utilizando essa estratégia seria o suficiente para manter o sistema internacionalizável. Se teria as informações suficientes para poder recuperar tanto a moeda quanto o valor numérico, porém, seria mais difícil, por exemplo, usar recursos do banco de dados, por exemplo, realizar somatório, assim um somatório teria que ser serializado para o modelo e assim a operação ser realizada.

  • Persistir o número e a moeda em campos diferentes: Essa opção, infelizmente, não está disponível no JPA, conforme foi discutido anteriormente no JPA 2.1 o converter apenas aceita um único campo como converção. Porém, é possível utilizar o hibernate diretamente para realizar essa operação, algo bem semelhante ao JPA 2.1, porém implementando a interface CompositeUserType. Com isso é possível, realizar operações de soma dentro do banco de dados, porém, existe a possibilidade de somar sem levar em consideração da moeda, ou não levar em consideração o modo de arredondamento desejado, que as implementações do MonetaryAmount podem garantir.

O Jadira é um framework que possui diversas implementações do UserType, interface que define o tipo que será persistido no banco de dados semelhante ao AttributeConverter. O Jadira já possui suporte tanto para as JSR 310, time-api, quanto o JSR 354, money-api.

CDI

Não é interessante que a entidade Livro seja responsável por definir a moeda que o objeto vai utilizar, afinal, não é sua responsabilidade. Outro ponto é que existem diversas estratégias para a criação de uma moeda: Definir a moeda a partir do usuário ou definir a moeda a partir do tenancy, por exemplo, caso o usuário utilize as máquinas do “.com.br” a moeda será real, “.com.us” dollar etc. Em nenhum desses casos deixar essa lógica espalhada no código não é uma boa estratégia, ou deixar o livro responsável por isso, nesse caso haverá quebra do SOLID. Para isso, poderíamos utilizar o CDI. O contexto de injeção de dependência, CDI, funciona basicamente como cola no mundo Java EE.

public class MoneyProducer { 

    @Inject 
    private HttpServletRequest request; 

    @Produces 
    @RequestScoped 
    public CurrencyUnit getCurrency() { 
        return Monetary.getCurrency(request.getLocale()); 
    } 
} 

Criar uma moeda a partir do request

public class MoneyProducer { 

    @Inject 
    @Named(&amp;quot;money_from_configurations&amp;quot;) 
    private String money; 

    @Produces 
    @RequestScoped 
    public CurrencyUnit getCurrency() { 
        return Monetary.getCurrency(money); 
    } 
}

Pegando a informação da moeda a partir de uma configuração.

Com um produtor de moeda definida pelo CDI, se pode injetar a moeda e “magicamente” ela será instanciada. Para não ter diversos pontos injetando moeda e criando dinheiro com ‘n’ implementações, uma recomendação é ter uma classe especializada na criação do dinheiro, caso seja necessário, criar um qualificadores para definir cada tipo de implementação.

public class MonetaryAmountFactory { 

    @Inject 
    private CurrencyUnit currency; 
    
    
    public MonetaryAmount create(Number number) { 
        return Money.of(number, currency); 
    } 

} 

 

JAX-RS

É muito comum, realizar integração com outros sistemas e para realizá-lo, o modo mais comum, é via uma API rest, dessa forma a integração será transparente pela tecnologia, linguagem, etc. que o outro sistema utilize. No mundo Java EE existe a especificação que lida com isso, o JAX-RS. Assim como na implementação de JPA, não existe um converter nativo para a moeda, a interface CurrencyUnit, e para o dinheiro, a interface MonetaryAmount. Na nova versão do JAX-RS é possível criar os próprios converters, para isso é necessário:

Implementar a interface ParamConverterProvider e anota-la com a anotação @Provider. Essa interface tem apenas um método e como saida espera como saida a interface ParamConverter.

@Provider 
public class MonetaryAmountConverterProvider implements ParamConverterProvider { 


    @Override 
    public &amp;amp;lt;T&amp;amp;gt; ParamConverter&amp;amp;lt;T&amp;amp;gt; getConverter(Class&amp;amp;lt;T&amp;amp;gt; rawType, Type genericType, Annotation[] annotations) { 
        if (MonetaryAmount.class.isInstance(rawType)) { 
            return new ParamConverter&amp;amp;lt;T&amp;amp;gt;() { 
                @Override 
                public T fromString(String value) { 
                    if(value == null || value.isEmpty()) { 
                        return null; 
                    } 
                    return rawType.cast(Money.parse(value)); 
                } 

                @Override 
                public String toString(T value) { 
                    if(value == null) { 
                        return null; 
                    } 
                    return value.toString(); 
                } 
            }; 
        } 
        return null; 
    } 
} 


@Provider 
public class CurrencyUnitConverterProvider implements ParamConverterProvider { 

    private CurrencyUnitParamConverter converter = new CurrencyUnitParamConverter(); 

    @Override 
    public &amp;amp;lt;T&amp;amp;gt; ParamConverter&amp;amp;lt;T&amp;amp;gt; getConverter(Class&amp;amp;lt;T&amp;amp;gt; rawType, Type genericType, Annotation[] annotations) { 
        if (CurrencyUnit.class.isInstance(rawType)) { 
            return new ParamConverter&amp;amp;lt;T&amp;amp;gt;() { 
                @Override 
                public T fromString(String value) { 
                    if(value == null || value.isEmpty()) { 
                        return null; 
                    } 
                    return rawType.cast(Monetary.getCurrency(value)); 
                } 

                @Override 
                public String toString(T value) { 
                    if(value == null) { 
                        return null; 
                    } 
                    return value.toString(); 
                } 
            }; 
        } 
            return null; 
    } 
}

JSF

A interação com o usuário é um ponto muito importante nas aplicações, assim é necessário representar o dinheiro e permitir que o usuário informe a moeda ou dinheiro. Assim como as outras especificações do mundo Java EE, não existe suporte para a money-api, porém existe converters dos componentes do JSF. Para isso basta implementar a interface Converter.

@FacesConverter(&amp;quot;money.midas.CurrencyConverter&amp;quot;) 
public class CurrencyConverter implements Converter { 

	@Override 
	public Object getAsObject(FacesContext context, UIComponent component, 
			String value) { 
		 
		if (Objects.isNull(value)) { 
			return null; 
		} 
		return Monetary.getCurrency(value); 
	} 

	@Override 
	public String getAsString(FacesContext context, UIComponent component, 
			Object value) { 
		if (Objects.isNull(value)) { 
			return null; 
		} 
		return value.toString(); 
	} 

} 

@FacesConverter(&amp;quot;money.midas.MoneyConverter&amp;quot;) 
public class MoneyConverter implements Converter { 

	@Override 
	public Object getAsObject(FacesContext context, UIComponent component, 
			String value) { 
		 
		if (Objects.isNull(value)) { 
			return null; 
		} 
		return Money.parse(value); 
	} 

	@Override 
&amp;amp;lt;strong&amp;amp;gt;	public String getAsString(FacesContext context, UIComponent component, 
			Object value) { 
		if (Objects.isNull(value)) { 
			return null;
		} 
		return value.toString(); 
	} 
}

O Projeto Midas

Com o intuito de realizar a integração entre as especificaçõeshttp://jadira.sourceforge.net/ e outros frameworks e o money-api existe o projeto Midas, dentre os projetos que estão no midas dar suporte estão:

  • JSF
  • Bean Validation
  • JPA
  • JAX-RS
  • CDI
  • Google Guice
  • Spring

No midas, todos os converters do JSF, JPA, JAX-RS que foram citatos nesse artigo estão nesse projeto. Além dessas especificações, o midas tem suporte para o bean validation.

  • CurrencyAccepted: Define as moedas que serão aceitas dentro da moeda, CurrencyUnit, e do dinheiro, MonetaryAmount. É possível informar as moedas permitidas ou usando o código da moeda ou de * o Locale de onda a moeda veio.
  • CurrencyRejected: Define as moedas que não serão aceitas, rejeitadas, dentro da moeda, CurrencyUnit, e do dinheiro, MonetaryAmount. É possível informar as moedas permitidas ou usando o * código da moeda ou de o Locale de onda a moeda veio.
  • MonetaryMax: Define o valor máximo para o dinheiro.
  • MonetaryMin: Define um valor mínimo para o dinheiro.
@CurrencyAccepted(currencies = &amp;quot;BRL&amp;quot;) 
private CurrencyUnit currencyUnit; 

@CurrencyAccepted(currencies = &amp;quot;BRL&amp;quot;) 
@MonetaryMax(&amp;quot;10.12&amp;quot;) 
private MonetaryAmount money;

Com isso foi apresentado a integração entre o money-api e o Java EE. Ainda existe muito mais integrações para serem desenvolvidas com essa espificação que trabalha com dinheiro e , certamente, toda ajuda será bem-vinda por todos os membros da comunidade.

Referências