Skip to content

Instantly share code, notes, and snippets.

@vndmtrx
Created September 21, 2024 12:28
Show Gist options
  • Save vndmtrx/6b8f0e9711d16f36f74f6c948b2723f1 to your computer and use it in GitHub Desktop.
Save vndmtrx/6b8f0e9711d16f36f74f6c948b2723f1 to your computer and use it in GitHub Desktop.
Gerador de UUID versão 7 compatível com Java 22, Spring Boot Data JPA e Hibernate.
/*
* Copyright 2023 Eduardo Rolim
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.vndmtrx;
import java.io.Serializable;
import java.time.Instant;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;
import java.util.function.LongFunction;
import java.util.function.LongSupplier;
import java.util.function.LongUnaryOperator;
import java.util.function.Supplier;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
/**
* Gerador de UUID versão 7 compatível com Java 22, Spring Boot Data JPA e Hibernate.
* Implementa a especificação UUID v7 (draft-peabody-dispatch-new-uuid-format-04).
*
* <p>Formas de uso:
* <pre>{@code
* // Geração direta de UUID (contexto imperativo)
* UUID uuid = UUIDv7.gerar.get();
*
* // Uso em streams (contexto funcional)
* List<UUID> uuids = Stream.generate(UUIDv7.gerar)
* .limit(10)
* .collect(Collectors.toList());
*
* // Uso em mapeamentos funcionais com of()
* List<String> ids = entidades.stream()
* .map(UUIDv7.of())
* .map(UUID::toString)
* .collect(Collectors.toList());
* }</pre>
*
* @author Eduardo Rolim
* @version 3.1.0
* @see <a href="https://github.com/vndmtrx">Perfil no GitHub</a>
*/
public class UUIDv7 implements IdentifierGenerator {
private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current();
private static final LongSupplier geradorMarcaTemporal = () -> Instant.now().toEpochMilli();
private static final LongUnaryOperator mascaraMSB = valor -> (valor & 0xFFFFFFFFFFFL) << 16;
private static final LongUnaryOperator mascaraVersao = valor -> valor | 0x7000L;
private static final LongUnaryOperator mascaraVariante = valor -> valor | 0x8000000000000000L;
private static final LongUnaryOperator mascaraRandA = valor -> valor & 0xFFFL;
private static final LongUnaryOperator mascaraRandB = valor -> valor & 0x3FFFFFFFFFFFFFFFL;
private static final LongFunction<Long> geraMSB = marcaTemporal -> {
long msbMarcaTemporal = mascaraMSB.applyAsLong(marcaTemporal);
long msbComVersao = mascaraVersao.applyAsLong(msbMarcaTemporal);
long msbRandA = mascaraRandA.applyAsLong(RANDOM.nextLong());
return msbComVersao | msbRandA;
};
private static final LongSupplier geraLSB = () -> {
long lsbRandB = mascaraRandB.applyAsLong(RANDOM.nextLong());
return mascaraVariante.applyAsLong(lsbRandB);
};
/**
* Gerador de UUID v7.
* Pode ser usado tanto em contextos funcionais quanto imperativos.
*/
public static final Supplier<UUID> gerar = () ->
new UUID(geraMSB.apply(geradorMarcaTemporal.getAsLong()), geraLSB.getAsLong());
/**
* Retorna uma função geradora de UUID v7.
*
* <p>Este método segue a convenção de nomenclatura "of" comum em Java para métodos de fábrica.
* Ele fornece uma função que pode ser usada em contextos funcionais, como streams ou mapeamentos.
*
* <p>Exemplo de uso:
* <pre>{@code
* List<String> ids = entidades.stream()
* .map(UUIDv7.of())
* .map(UUID::toString)
* .collect(Collectors.toList());
* }</pre>
*
* @return Uma função que, quando chamada, gera um novo UUID v7
*/
public static Function<Void, UUID> of() {
return _ -> gerar.get();
}
/**
* Gera um identificador para o Hibernate.
*
* <p>Uso com Hibernate:
* <pre>{@code
* @Id
* @GeneratedValue(generator = "UUID")
* @GenericGenerator(
* name = "UUID",
* strategy = "io.github.vndmtrx.UUIDv7"
* )
* private UUID id;
* }</pre>
*
* @param sessao A sessão atual
* @param objeto A entidade para a qual o identificador está sendo gerado
* @return Um novo UUID versão 7
* @throws HibernateException se houver um erro durante a geração
*/
@Override
public Serializable generate(SharedSessionContractImplementor sessao, Object objeto) throws HibernateException {
return gerar.get();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment