uk.dansiviter.cdi.repos.Util Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2023 Daniel Siviter
*
* 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 uk.dansiviter.cdi.repos;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.stream.Stream;
import jakarta.persistence.EntityManager;
import jakarta.persistence.NonUniqueResultException;
/**
* Utilities for use with generated repositories.
*/
public enum Util { ;
/**
* Analyses the entity and returns if it is new or not. This is based on the key being either {@code null} or if
* it is a primitive number is zero.
*
* @param entity the entity to analyze.
* @param em the entity manager associated with the entity.
* @return {@code true} if it is a new entity.
*/
public static boolean isNew(Object entity, EntityManager em) {
var id = em.getEntityManagerFactory().getPersistenceUnitUtil().getIdentifier(entity);
if (id == null) {
return true;
}
if (id instanceof Number n) {
return n.intValue() == 0;
}
return false;
}
/**
* Either uses {@link EntityManager#persist(Object) #persist(Object)} or
* {@link EntityManager#merge(Object) #merge(Object)} depending on the result of
* {@link #isNew(Object, EntityManager)}.
*
* @param the entity type.
* @param entity the entity to save.
* @param em the entity manager associated with the entity.
* @return the saved value.
* @see #isNew(Object, EntityManager)
*/
public static T save(T entity, EntityManager em) {
if (isNew(entity, em)) {
em.persist(entity);
return entity;
}
return em.merge(entity);
}
/**
* Horrible convenience method to unwrap the value.
*
* @param opt the optional to extract from.
* @return a Integer or {@code null}.
*/
public static Integer orElseNull(OptionalInt opt) {
return opt.isPresent() ? Integer.valueOf(opt.getAsInt()) : null;
}
/**
* Horrible convenience method to unwrap the value.
*
* @param opt the optional to extract from.
* @return a Long or {@code null}.
*/
public static Long orElseNull(OptionalLong opt) {
return opt.isPresent() ? Long.valueOf(opt.getAsLong()) : null;
}
/**
* Horrible convenience method to unwrap the value.
*
* @param opt the optional to extract from.
* @return a Double or {@code null}.
*/
public static Double orElseNull(OptionalDouble opt) {
return opt.isPresent() ? Double.valueOf(opt.getAsDouble()) : null;
}
/**
* Returns a single result from the stream. Useful when you expect only one result.
*
* @param the object type.
* @param stream the stream to use.
* @return an optional result.
* @throws IllegalStateException if there is more than one result in the stream.
*/
public static Optional toOptional(Stream stream) {
return stream
.filter(Objects::nonNull)
.reduce(Util::throwNonUnique);
}
/**
* Returns a single result from the stream. Useful when you expect only one result.
*
* @param the number type.
* @param stream the stream to use.
* @return an optional result.
* @throws IllegalStateException if there is more than one result in the stream.
*/
public static OptionalInt toOptionalInt(Stream stream) {
return stream
.filter(Objects::nonNull)
.mapToInt(Number::intValue)
.reduce(Util::throwNonUnique);
}
/**
* Returns a single result from the stream. Useful when you expect only one result.
*
* @param the number type.
* @param stream the stream to use.
* @return an optional result.
* @throws IllegalStateException if there is more than one result in the stream.
*/
public static OptionalLong toOptionalLong(Stream stream) {
return stream
.filter(Objects::nonNull)
.mapToLong(Number::longValue)
.reduce(Util::throwNonUnique);
}
/**
* Returns a single result from the stream. Useful when you expect only one result.
*
* @param the number type.
* @param stream the stream to use.
* @return an optional result.
* @throws IllegalStateException if there is more than one result in the stream.
*/
public static OptionalDouble toOptionalDouble(Stream stream) {
return stream
.filter(Objects::nonNull)
.mapToDouble(Number::doubleValue)
.reduce(Util::throwNonUnique);
}
private static V throwNonUnique(T t, U u) {
throw new NonUniqueResultException("More than one result");
}
}