package org.springframework.roo.addon.layers.repository.jpa.addon; import static org.springframework.roo.classpath.customdata.CustomDataKeys.COUNT_ALL_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.FIND_ALL_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.FIND_ENTRIES_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.FIND_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.FLUSH_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.MERGE_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.PERSIST_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.REMOVE_METHOD; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.apache.commons.lang3.Validate; import org.springframework.roo.classpath.customdata.tagkeys.MethodMetadataCustomDataKey; import org.springframework.roo.classpath.layers.LayerType; import org.springframework.roo.classpath.layers.MethodParameter; import org.springframework.roo.model.JavaSymbolName; import org.springframework.roo.model.JavaType; /** * A method provided by the {@link LayerType#REPOSITORY} layer. * <p> * A Spring Data JPA repository provides the following methods out of the box, * of which those marked * are not implemented below: * * <pre> * long count() * *void delete(ID) * *void delete(Iterable<? extends T>) * void delete(T) * *void deleteAll() * *void deleteInBatch(Iterable<T>) * *boolean exists(ID) * List<T> findAll() * *org.springframework.data.domain.Page<T> findAll(org.springframework.data.domain.Pageable) * *List<T> findAll(org.springframework.data.domain.Sort) * T findOne(ID) * void flush() * *List<T> save(Iterable<? extends T>) * T save(T) * *T saveAndFlush(T) * </pre> * * @author Andrew Swan * @since 1.2.0 */ public enum RepositoryJpaLayerMethod { COUNT("count", COUNT_ALL_METHOD) { @Override public String getCall(final List<MethodParameter> parameters) { return "count()"; } @Override protected List<JavaType> getParameterTypes(final JavaType targetEntity, final JavaType idType) { return Collections.emptyList(); } }, /** * Deletes the passed-in entity (does not delete by ID). */ DELETE("delete", REMOVE_METHOD) { @Override public String getCall(final List<MethodParameter> parameters) { return "delete(" + parameters.get(0).getValue() + ")"; } @Override protected List<JavaType> getParameterTypes(final JavaType targetEntity, final JavaType idType) { return Arrays.asList(targetEntity); } }, FIND("find", FIND_METHOD) { @Override public String getCall(final List<MethodParameter> parameters) { return "findOne(" + parameters.get(0).getValue() + ")"; } @Override protected List<JavaType> getParameterTypes(final JavaType entityType, final JavaType idType) { return Arrays.asList(idType); } }, FIND_ALL("findAll", FIND_ALL_METHOD) { @Override public String getCall(final List<MethodParameter> parameters) { return "findAll()"; } @Override protected List<JavaType> getParameterTypes(final JavaType targetEntity, final JavaType idType) { return Collections.emptyList(); } }, /** * Finds entities starting from a given zero-based index, up to a given * maximum number of results. This method isn't directly implemented by * Spring Data JPA, so we use its findAll(Pageable) API. */ FIND_ENTRIES("findEntries", FIND_ENTRIES_METHOD) { @Override public String getCall(final List<MethodParameter> parameters) { final JavaSymbolName firstResultParameter = parameters.get(0).getValue(); final JavaSymbolName maxResultsParameter = parameters.get(1).getValue(); final String pageNumberExpression = firstResultParameter + " / " + maxResultsParameter; return "findAll(new org.springframework.data.domain.PageRequest(" + pageNumberExpression + ", " + maxResultsParameter + ")).getContent()"; } @Override protected List<JavaType> getParameterTypes(final JavaType targetEntity, final JavaType idType) { return Arrays.asList(JavaType.INT_PRIMITIVE, JavaType.INT_PRIMITIVE); } }, FLUSH("flush", FLUSH_METHOD) { @Override public String getCall(final List<MethodParameter> parameters) { return "flush()"; } @Override protected List<JavaType> getParameterTypes(final JavaType targetEntity, final JavaType idType) { // Even though Spring Data JPA's flush() method doesn't take a // parameter, the caller provides one, so we list it here. return Arrays.asList(targetEntity); } }, /** * Spring Data JPA makes no distinction between * create/persist/save/update/merge */ SAVE("save", MERGE_METHOD, PERSIST_METHOD) { @Override public String getCall(final List<MethodParameter> parameters) { return "save(" + parameters.get(0).getValue() + ")"; } @Override protected List<JavaType> getParameterTypes(final JavaType targetEntity, final JavaType idType) { return Arrays.asList(targetEntity); } }; /** * Returns the {@link RepositoryJpaLayerMethod} with the given ID and * parameter types. * * @param methodId the ID to match upon * @param parameterTypes the parameter types to match upon * @param targetEntity the entity type being managed by the repository * @param idType specifies the ID type used by the target entity (required) * @return <code>null</code> if no such method exists */ public static RepositoryJpaLayerMethod valueOf(final String methodId, final List<JavaType> parameterTypes, final JavaType targetEntity, final JavaType idType) { for (final RepositoryJpaLayerMethod method : values()) { if (method.ids.contains(methodId) && method.getParameterTypes(targetEntity, idType).equals(parameterTypes)) { return method; } } return null; } private final List<String> ids; private final String name; /** * Constructor * * @param key the unique key for this method (required) * @param name the Java name of this method (required) */ private RepositoryJpaLayerMethod(final String name, final MethodMetadataCustomDataKey... keys) { Validate.notBlank(name, "Name is required"); Validate.isTrue(keys.length > 0, "One or more ids are required"); ids = new ArrayList<String>(); for (final MethodMetadataCustomDataKey key : keys) { ids.add(key.name()); } this.name = name; } /** * Returns a Java snippet that invokes this method (minus the target) * * @param parameters the parameters used by the caller; can be * <code>null</code> * @return a non-blank Java snippet */ public abstract String getCall(List<MethodParameter> parameters); /** * Returns the name of this method * * @return a non-blank name */ public String getName() { return name; } /** * Instances must return the types of parameters they take * * @param targetEntity the type of entity being managed (required) * @param idType specifies the ID type used by the target entity (required) * @return a non-<code>null</code> list */ protected abstract List<JavaType> getParameterTypes(JavaType targetEntity, JavaType idType); }