001/* 002 * Copyright (C) 2022 - 2024, the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.github.ascopes.jct.compilers; 017 018/** 019 * Function representing a configuration operation that can be applied to a compiler. 020 * 021 * <p>This can allow encapsulating common configuration logic across tests into a single place. 022 * 023 * <p>Implementations of this interface should declare the exception type that the implementation 024 * can throw when invoked. If this is not a checked exception, or no case exists where an exception 025 * could be thrown, then this can be set to {@link RuntimeException}. 026 * 027 * <p>The following demonstrates an example usage of this interface. The implementation configures 028 * a specific annotation processor and sets an annotation processor flag. 029 * 030 * <pre><code> 031 * class MyAnnotationProcessorConfigurer implements JctCompilerConfigurer<RuntimeException> { 032 * {@literal @Override} 033 * public void configure(JctCompiler compiler) { 034 * compiler 035 * .addAnnotationProcessors(new MyAnnotationProcessor()) 036 * .addAnnotationProcessorOptions("MyAnnotationProcessor.debug=true"); 037 * } 038 * } 039 * </code></pre> 040 * 041 * <p>...tests can then make use of this configurer directly: 042 * 043 * <pre><code> 044 * {@literal @Test} 045 * void theCompilationSucceedsAsExpected() { 046 * try (var workspace = Workspaces.newWorkspace()) { 047 * // Given 048 * ... 049 * 050 * var compiler = JctCompilers 051 * .newPlatformCompiler() 052 * .release(17) 053 * .configure(new MyAnnotationProcessorConfigurer()); 054 * 055 * // When 056 * var compilation = compiler.compile(workspace); 057 * 058 * // Then 059 * ... 060 * } 061 * } 062 * </code></pre> 063 * 064 * <p>Since this is a functional interface, configurers can be lambda expressions, anonymous 065 * objects, or method references. 066 * 067 * <pre><code> 068 * compiler 069 * .configure(c -> c.release(11)) 070 * .configure(this::configureFailures); 071 * </code></pre> 072 * 073 * <p>The JUnit support allows for specifying these configurers in an annotation instead. This 074 * will apply the configurer before passing it to the test as a parameter: 075 * 076 * <pre><code> 077 * {@literal @JavacCompilersTest(configurers = {MyAnnotationProcessorConfigurer.class})} 078 * void theCompilationSucceedsAsExpected(JctCompiler compiler) { 079 * // ... 080 * } 081 * </code></pre> 082 * 083 * <p>Note that in this case, the configurer must be an outer class or a static nested class 084 * rather than a Lambda expression, anonymous class, class instance, or nested class. It must also 085 * have a single public no-arguments constructor in order to be accessible. 086 * 087 * @param <E> the exception that may be thrown by the configurer. 088 * @author Ashley Scopes 089 * @since 0.0.1 090 */ 091@FunctionalInterface 092public interface JctCompilerConfigurer<E extends Exception> { 093 094 /** 095 * Apply configuration logic to the given compiler. 096 * 097 * @param compiler the compiler. 098 * @throws E any exception that may be thrown by the configurer. 099 */ 100 void configure(JctCompiler compiler) throws E; 101}