mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-07 12:24:58 +10:00
@@ -7,7 +7,7 @@ that file before editing anything under `diylc/`.
|
||||
|
||||
| Path | Contents |
|
||||
| --- | --- |
|
||||
| `diylc/` | The application. Maven reactor with `diylc-core`, `diylc-library`, `diylc-swing`. This is where nearly all work happens. |
|
||||
| `diylc/` | The application. Maven reactor with `diylc-core`, `diylc-library`, `diylc-swing`, and the build-time `diylc-processor`. This is where nearly all work happens. |
|
||||
| `diylc-regression-data/` | Sample `.diy` projects plus reference PNG and netlist outputs used by the regression suite, and the historical reports. |
|
||||
| `diylc-server-api/` | PHP backend for cloud and collaboration features. Runs in an isolated environment on diy-fever.com and cannot be tested locally — do not modify unless explicitly asked. |
|
||||
| `snap/` | Snap packaging metadata. |
|
||||
|
||||
@@ -6,7 +6,8 @@ description: Add a new component type to the DIYLC library, or substantially mod
|
||||
# Adding a component to DIYLC
|
||||
|
||||
Components live in `diylc-library/src/main/java/org/diylc/components/`. They are discovered at
|
||||
runtime by Reflections scanning `org.diylc` — **there is no registry to update**. A class becomes a
|
||||
runtime from a class index that `diylc-processor` writes at compile time — **there is no registry
|
||||
to update**. A class becomes a
|
||||
component by carrying `@ComponentDescriptor` and implementing `IDIYComponent` (in practice, by
|
||||
extending one of the abstract bases).
|
||||
|
||||
|
||||
+8
-4
@@ -15,14 +15,15 @@ if it compiles and works.
|
||||
|
||||
## Modules
|
||||
|
||||
Maven reactor rooted at `diylc/pom.xml`, version `6.4.0`, three modules with a strict one-way
|
||||
dependency chain:
|
||||
Maven reactor rooted at `diylc/pom.xml`, version `6.4.0`, three application modules with a strict
|
||||
one-way dependency chain, plus a build-time annotation processor:
|
||||
|
||||
| Module | Contains | Depends on |
|
||||
| --- | --- | --- |
|
||||
| `diylc-core` | Domain model, `Presenter`, rendering pipeline, messaging, serialization, netlist engine, annotations | — |
|
||||
| `diylc-library` | Concrete component classes, transformers, datasheets, legacy file parsers, component-aware analyzers | `diylc-core` |
|
||||
| `diylc-swing` | Swing shell, plugins, dialogs, editors, `DIYLCStarter` | `diylc-core`, `diylc-library` |
|
||||
| `diylc-processor` | `ServiceIndexProcessor`, run by `javac` over the three modules above; never on the runtime classpath | — |
|
||||
|
||||
**`diylc-core` must never reference a concrete component type.** It knows components only through
|
||||
`IDIYComponent` and the annotations. If core logic seems to need knowledge of a specific component,
|
||||
@@ -30,8 +31,11 @@ that knowledge belongs in `diylc-library` (an analyzer, a transformer, a parser)
|
||||
through a new interface in core that the component implements — look at
|
||||
`org.diylc.core.gerber.IGerberComponentSimple` for the established shape of that escape hatch.
|
||||
|
||||
Component and plugin classes are discovered at runtime by Reflections scanning the `org.diylc`
|
||||
package (`ComponentProcessor`). There is no registry to update when adding a component.
|
||||
Components, netlist analyzers and parsers, legacy file parsers and auto-creators are discovered
|
||||
through a class index built at compile time: every concrete class implementing a type marked
|
||||
`@Indexed` (`IDIYComponent`, `INetlistAnalyzer`, ...) is listed under `META-INF/services/` by
|
||||
`diylc-processor`, and `ReflectionUtils.getIndexedClasses()` reads that back at startup. Nothing
|
||||
scans the classpath, and there is no registry to update when adding a component.
|
||||
|
||||
## Build and verify
|
||||
|
||||
|
||||
@@ -19,6 +19,12 @@
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Internal module dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-processor</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Common dependencies from Maven Central -->
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
@@ -52,11 +58,6 @@
|
||||
<artifactId>jettison</artifactId>
|
||||
<version>1.5.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.reflections</groupId>
|
||||
<artifactId>reflections</artifactId>
|
||||
<version>0.10.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
|
||||
@@ -24,11 +24,13 @@ package org.diylc.common;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.diylc.core.annotations.Indexed;
|
||||
import org.diylc.netlist.Netlist;
|
||||
import org.diylc.netlist.Node;
|
||||
import org.diylc.netlist.Summary;
|
||||
import org.diylc.netlist.TreeException;
|
||||
|
||||
@Indexed
|
||||
public interface INetlistAnalyzer {
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.util.UUID;
|
||||
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.Indexed;
|
||||
|
||||
/**
|
||||
* Interface for component instance. Implementation classes of this interface will be instantiated
|
||||
@@ -47,6 +48,7 @@ import org.diylc.core.annotations.EditableProperty;
|
||||
*
|
||||
* @param <T> type of component values, e.g. Resistance for resistors or String for transistors.
|
||||
*/
|
||||
@Indexed
|
||||
public interface IDIYComponent<T> extends Serializable, Cloneable {
|
||||
|
||||
public static final int CHASSIS = 1;
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.diylc.core.IDIYComponent;
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
@Indexed
|
||||
public interface IAutoCreator {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.core.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.diylc.utils.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Marks a type whose concrete implementations are discovered at runtime. The
|
||||
* {@code diylc-processor} annotation processor lists them under {@code META-INF/services} when
|
||||
* the implementing module is compiled, and {@link ReflectionUtils#getIndexedClasses(Class)} reads
|
||||
* that list back, so nothing has to scan the classpath. An implementation is picked up just by
|
||||
* implementing the type; there is no registry to update.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Indexed {
|
||||
|
||||
}
|
||||
@@ -2,6 +2,9 @@ package org.diylc.netlist;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.diylc.core.annotations.Indexed;
|
||||
|
||||
@Indexed
|
||||
public interface IGuitarDiagramAnalyzer {
|
||||
|
||||
List<String> collectNotes(Netlist netlist);
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.annotations.Indexed;
|
||||
|
||||
/*
|
||||
*
|
||||
@@ -41,6 +42,7 @@ import org.diylc.core.IDIYComponent;
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
@Indexed
|
||||
public interface INetlistParser {
|
||||
|
||||
String getName();
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.presenter;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.diylc.core.IDIYComponent;
|
||||
|
||||
/**
|
||||
* Toolbox icon of a component type. Drawing it means instantiating the component, so it is
|
||||
* deferred until the icon is first painted rather than done for every type at startup.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
class ComponentIcon implements Icon {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(ComponentIcon.class);
|
||||
|
||||
private final Class<? extends IDIYComponent<?>> componentClass;
|
||||
private BufferedImage image;
|
||||
|
||||
ComponentIcon(Class<? extends IDIYComponent<?>> componentClass) {
|
||||
this.componentClass = componentClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintIcon(Component c, Graphics g, int x, int y) {
|
||||
if (image == null) {
|
||||
image = drawImage();
|
||||
}
|
||||
g.drawImage(image, x, y, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
return Presenter.ICON_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconHeight() {
|
||||
return Presenter.ICON_SIZE;
|
||||
}
|
||||
|
||||
private BufferedImage drawImage() {
|
||||
BufferedImage image =
|
||||
new BufferedImage(Presenter.ICON_SIZE, Presenter.ICON_SIZE, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = image.createGraphics();
|
||||
try {
|
||||
IDIYComponent<?> componentInstance = componentClass.getDeclaredConstructor().newInstance();
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
|
||||
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
|
||||
componentInstance.drawIcon(g2d, Presenter.ICON_SIZE, Presenter.ICON_SIZE);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error drawing component icon for " + componentClass.getName(), e);
|
||||
} finally {
|
||||
g2d.dispose();
|
||||
}
|
||||
return image;
|
||||
}
|
||||
}
|
||||
@@ -21,19 +21,13 @@
|
||||
*/
|
||||
package org.diylc.presenter;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.diylc.common.ComponentType;
|
||||
@@ -53,11 +47,7 @@ import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.KeywordPolicy;
|
||||
|
||||
import org.diylc.lang.LangUtil;
|
||||
import org.reflections.Reflections;
|
||||
import org.reflections.util.ConfigurationBuilder;
|
||||
import org.reflections.util.FilterBuilder;
|
||||
|
||||
import static org.reflections.scanners.Scanners.TypesAnnotated;
|
||||
import org.diylc.utils.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Utility class with component processing methods.
|
||||
@@ -138,26 +128,7 @@ public class ComponentProcessor {
|
||||
} else { // default
|
||||
return null;
|
||||
}
|
||||
icon = null;
|
||||
// Draw component icon.
|
||||
try {
|
||||
IDIYComponent<?> componentInstance = (IDIYComponent<?>) clazz.getDeclaredConstructor().newInstance();
|
||||
Image image =
|
||||
new BufferedImage(Presenter.ICON_SIZE, Presenter.ICON_SIZE, java.awt.image.BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = (Graphics2D) image.getGraphics();
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
|
||||
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
|
||||
// g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
|
||||
// RenderingHints.VALUE_STROKE_PURE);
|
||||
componentInstance.drawIcon(g2d, Presenter.ICON_SIZE, Presenter.ICON_SIZE);
|
||||
icon = new ImageIcon(image);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error drawing component icon", e);
|
||||
}
|
||||
icon = new ComponentIcon(clazz);
|
||||
ComponentType componentType =
|
||||
new ComponentType(name, description, creationMethod, category, namePrefix, author, icon, clazz, zOrder,
|
||||
flexibleZOrder, bomPolicy, autoEdit, transformer, keywordPolicy, keywordTag, cacheDrawing, datasheet,
|
||||
@@ -254,64 +225,57 @@ public class ComponentProcessor {
|
||||
if (componentTypes == null) {
|
||||
LOG.info("Loading component types.");
|
||||
componentTypes = new HashMap<String, List<ComponentType>>();
|
||||
Reflections reflections = new Reflections(
|
||||
new ConfigurationBuilder()
|
||||
.forPackage("org.diylc")
|
||||
.filterInputsBy(new FilterBuilder().includePackage("org.diylc.components"))
|
||||
.setScanners(TypesAnnotated));
|
||||
Set<Class<?>> componentTypeClasses = null;
|
||||
try {
|
||||
componentTypeClasses = reflections.getTypesAnnotatedWith(ComponentDescriptor.class, false);
|
||||
List<Map<String, Object>> componentSnapshots = LOG_COMPONENT_TYPE_DETAILS ? new ArrayList<>() : null;
|
||||
|
||||
for (Class<?> clazz : componentTypeClasses) {
|
||||
if (!Modifier.isAbstract(clazz.getModifiers()) && IDIYComponent.class.isAssignableFrom(clazz)) {
|
||||
ComponentType componentType =
|
||||
ComponentProcessor.getInstance().extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) clazz);
|
||||
if (componentType == null)
|
||||
continue;
|
||||
for (Class<?> clazz : ReflectionUtils.getIndexedClasses(IDIYComponent.class)) {
|
||||
ComponentType componentType =
|
||||
ComponentProcessor.getInstance().extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) clazz);
|
||||
if (componentType == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// just to store in the cache
|
||||
ComponentProcessor.getInstance().extractProperties(clazz);
|
||||
// just to store in the cache
|
||||
ComponentProcessor.getInstance().extractProperties(clazz);
|
||||
|
||||
// types created only programmatically (e.g. CompositeComponent) don't belong in the
|
||||
// palette, but still need to go through extractProperties() above so the cache is warm
|
||||
if (clazz.getAnnotation(ComponentDescriptor.class).hiddenInPalette())
|
||||
continue;
|
||||
// types created only programmatically (e.g. CompositeComponent) don't belong in the
|
||||
// palette, but still need to go through extractProperties() above so the cache is warm
|
||||
if (clazz.getAnnotation(ComponentDescriptor.class).hiddenInPalette()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<ComponentType> nestedList;
|
||||
if (componentTypes.containsKey(componentType.getCategory())) {
|
||||
nestedList = componentTypes.get(componentType.getCategory());
|
||||
} else {
|
||||
nestedList = new ArrayList<ComponentType>();
|
||||
componentTypes.put(componentType.getCategory(), nestedList);
|
||||
}
|
||||
nestedList.add(componentType);
|
||||
List<ComponentType> nestedList;
|
||||
if (componentTypes.containsKey(componentType.getCategory())) {
|
||||
nestedList = componentTypes.get(componentType.getCategory());
|
||||
} else {
|
||||
nestedList = new ArrayList<ComponentType>();
|
||||
componentTypes.put(componentType.getCategory(), nestedList);
|
||||
}
|
||||
nestedList.add(componentType);
|
||||
|
||||
if (LOG_COMPONENT_TYPE_DETAILS) {
|
||||
try {
|
||||
Map<String, Object> snapshot = new LinkedHashMap<>();
|
||||
snapshot.put("name", componentType.getName());
|
||||
snapshot.put("description", componentType.getDescription());
|
||||
snapshot.put("creationMethod", componentType.getCreationMethod());
|
||||
snapshot.put("category", componentType.getCategory());
|
||||
List<PropertyWrapper> props = propertyCache.get(clazz.getName());
|
||||
snapshot.put("properties", props != null ? props.stream()
|
||||
.map(p -> {
|
||||
Map<String, Object> prop = new LinkedHashMap<>();
|
||||
prop.put("name", p.getName());
|
||||
prop.put("type", formatPropertyType(p.getType()));
|
||||
List<String> possibleValues = getPossibleValues(p.getType());
|
||||
if (possibleValues != null) {
|
||||
prop.put("possibleValues", possibleValues);
|
||||
}
|
||||
return prop;
|
||||
})
|
||||
.collect(Collectors.toList()) : Collections.emptyList());
|
||||
componentSnapshots.add(snapshot);
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Failed to log component type details for " + clazz.getName(), e);
|
||||
}
|
||||
if (LOG_COMPONENT_TYPE_DETAILS) {
|
||||
try {
|
||||
Map<String, Object> snapshot = new LinkedHashMap<>();
|
||||
snapshot.put("name", componentType.getName());
|
||||
snapshot.put("description", componentType.getDescription());
|
||||
snapshot.put("creationMethod", componentType.getCreationMethod());
|
||||
snapshot.put("category", componentType.getCategory());
|
||||
List<PropertyWrapper> props = propertyCache.get(clazz.getName());
|
||||
snapshot.put("properties", props != null ? props.stream()
|
||||
.map(p -> {
|
||||
Map<String, Object> prop = new LinkedHashMap<>();
|
||||
prop.put("name", p.getName());
|
||||
prop.put("type", formatPropertyType(p.getType()));
|
||||
List<String> possibleValues = getPossibleValues(p.getType());
|
||||
if (possibleValues != null) {
|
||||
prop.put("possibleValues", possibleValues);
|
||||
}
|
||||
return prop;
|
||||
})
|
||||
.collect(Collectors.toList()) : Collections.emptyList());
|
||||
componentSnapshots.add(snapshot);
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Failed to log component type details for " + clazz.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
@@ -3133,16 +3132,8 @@ public class Presenter implements IPlugInPort {
|
||||
|
||||
@Override
|
||||
public List<INetlistAnalyzer> getNetlistAnalyzers() {
|
||||
Set<Class<?>> classes;
|
||||
try {
|
||||
classes = Utils.getClasses("org.diylc.netlist");
|
||||
List<INetlistAnalyzer> result = new ArrayList<INetlistAnalyzer>();
|
||||
|
||||
for (Class<?> clazz : classes) {
|
||||
if (!Modifier.isAbstract(clazz.getModifiers()) && INetlistAnalyzer.class.isAssignableFrom(clazz)) {
|
||||
result.add((INetlistAnalyzer) clazz.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
}
|
||||
List<INetlistAnalyzer> result = ReflectionUtils.getIndexedInstances(INetlistAnalyzer.class);
|
||||
|
||||
result.sort(new Comparator<INetlistAnalyzer>() {
|
||||
|
||||
|
||||
@@ -26,7 +26,9 @@ import java.util.List;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.annotations.Indexed;
|
||||
|
||||
@Indexed
|
||||
public interface IOldFileParser {
|
||||
|
||||
boolean canParse(String version);
|
||||
|
||||
@@ -30,7 +30,6 @@ import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@@ -41,7 +40,6 @@ import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.diylc.appframework.miscutils.Utils;
|
||||
import org.diylc.appframework.simplemq.MessageDispatcher;
|
||||
import org.diylc.appframework.update.VersionNumber;
|
||||
import org.w3c.dom.Document;
|
||||
@@ -59,6 +57,7 @@ import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.presenter.Presenter;
|
||||
import org.diylc.test.DIYTest;
|
||||
import org.diylc.utils.ReflectionUtils;
|
||||
|
||||
public class ProjectFileManager {
|
||||
|
||||
@@ -144,17 +143,10 @@ public class ProjectFileManager {
|
||||
|
||||
public List<IOldFileParser> getParsers() {
|
||||
if (parsers == null) {
|
||||
parsers = new ArrayList<IOldFileParser>();
|
||||
Set<Class<?>> componentTypeClasses = null;
|
||||
try {
|
||||
componentTypeClasses = Utils.getClasses("org.diylc.serialization");
|
||||
for (Class<?> clazz : componentTypeClasses) {
|
||||
if (!Modifier.isAbstract(clazz.getModifiers()) && IOldFileParser.class.isAssignableFrom(clazz)) {
|
||||
IOldFileParser instance = (IOldFileParser) clazz.getDeclaredConstructor().newInstance();
|
||||
parsers.add(instance);
|
||||
}
|
||||
}
|
||||
parsers = ReflectionUtils.getIndexedInstances(IOldFileParser.class);
|
||||
} catch (Exception e) {
|
||||
parsers = new ArrayList<IOldFileParser>();
|
||||
LOG.error("Could not find old version parsers", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,23 +21,30 @@
|
||||
*/
|
||||
package org.diylc.utils;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.diylc.appframework.miscutils.Utils;
|
||||
|
||||
import org.diylc.core.annotations.IAutoCreator;
|
||||
import org.diylc.core.annotations.Indexed;
|
||||
import org.diylc.netlist.IGuitarDiagramAnalyzer;
|
||||
import org.diylc.netlist.INetlistParser;
|
||||
import org.diylc.presenter.Presenter;
|
||||
|
||||
public class ReflectionUtils {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(Presenter.class);
|
||||
private static final Logger LOG = Logger.getLogger(ReflectionUtils.class);
|
||||
|
||||
private static final String SERVICES_DIR = "META-INF/services/";
|
||||
|
||||
/**
|
||||
* {@link List} of {@link IAutoCreator} objects that are capable of creating more components
|
||||
@@ -45,19 +52,66 @@ public class ReflectionUtils {
|
||||
*/
|
||||
private static List<IAutoCreator> autoCreators;
|
||||
|
||||
public static List<IAutoCreator> getAutoCreators() {
|
||||
if (autoCreators == null) {
|
||||
autoCreators = new ArrayList<IAutoCreator>();
|
||||
Set<Class<?>> classes = null;
|
||||
try {
|
||||
classes = Utils.getClasses("org.diylc.components.autocreate");
|
||||
for (Class<?> clazz : classes) {
|
||||
if (IAutoCreator.class.isAssignableFrom(clazz)) {
|
||||
autoCreators.add((IAutoCreator) clazz.getDeclaredConstructor().newInstance());
|
||||
LOG.debug("Loaded auto-creator: " + clazz.getName());
|
||||
/**
|
||||
* Returns the concrete implementations of an {@link Indexed} type, as listed at build time by
|
||||
* {@code diylc-processor}. Classes are loaded but not initialized.
|
||||
*/
|
||||
public static <T> List<Class<? extends T>> getIndexedClasses(Class<T> type) {
|
||||
ClassLoader classLoader = ReflectionUtils.class.getClassLoader();
|
||||
// each module jar carries its own index file for the same type
|
||||
Set<String> classNames = new LinkedHashSet<String>();
|
||||
try {
|
||||
Enumeration<URL> indexFiles = classLoader.getResources(SERVICES_DIR + type.getName());
|
||||
while (indexFiles.hasMoreElements()) {
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(indexFiles.nextElement().openStream(), StandardCharsets.UTF_8))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (!line.isEmpty() && !line.startsWith("#")) {
|
||||
classNames.add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Could not read the class index of " + type.getName(), e);
|
||||
}
|
||||
|
||||
List<Class<? extends T>> result = new ArrayList<Class<? extends T>>(classNames.size());
|
||||
for (String className : classNames) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(className, false, classLoader);
|
||||
if (type.isAssignableFrom(clazz)) {
|
||||
result.add(clazz.asSubclass(type));
|
||||
} else {
|
||||
LOG.warn("Class index of " + type.getName() + " lists unrelated class " + className);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
LOG.warn("Class index of " + type.getName() + " lists missing class " + className);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates every class returned by {@link #getIndexedClasses(Class)} through its no-arg
|
||||
* constructor.
|
||||
*/
|
||||
public static <T> List<T> getIndexedInstances(Class<T> type) throws ReflectiveOperationException {
|
||||
List<T> result = new ArrayList<T>();
|
||||
for (Class<? extends T> clazz : getIndexedClasses(type)) {
|
||||
result.add(clazz.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<IAutoCreator> getAutoCreators() {
|
||||
if (autoCreators == null) {
|
||||
try {
|
||||
autoCreators = getIndexedInstances(IAutoCreator.class);
|
||||
} catch (Exception e) {
|
||||
autoCreators = new ArrayList<IAutoCreator>();
|
||||
LOG.error("Error loading auto-creator types", e);
|
||||
}
|
||||
}
|
||||
@@ -65,16 +119,8 @@ public class ReflectionUtils {
|
||||
}
|
||||
|
||||
public static List<INetlistParser> getNetlistParserDefinitions() {
|
||||
Set<Class<?>> classes;
|
||||
try {
|
||||
classes = Utils.getClasses("org.diylc.netlist");
|
||||
List<INetlistParser> result = new ArrayList<INetlistParser>();
|
||||
|
||||
for (Class<?> clazz : classes) {
|
||||
if (!Modifier.isAbstract(clazz.getModifiers()) && INetlistParser.class.isAssignableFrom(clazz)) {
|
||||
result.add((INetlistParser) clazz.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
}
|
||||
List<INetlistParser> result = getIndexedInstances(INetlistParser.class);
|
||||
|
||||
Collections.sort(result, new Comparator<INetlistParser>() {
|
||||
|
||||
@@ -92,16 +138,7 @@ public class ReflectionUtils {
|
||||
}
|
||||
|
||||
public static IGuitarDiagramAnalyzer getGuitarDiagramAnalyzer() throws Exception {
|
||||
Set<Class<?>> classes;
|
||||
classes = Utils.getClasses("org.diylc.netlist");
|
||||
List<IGuitarDiagramAnalyzer> result = new ArrayList<>();
|
||||
|
||||
for (Class<?> clazz : classes) {
|
||||
if (!Modifier.isAbstract(clazz.getModifiers()) && IGuitarDiagramAnalyzer.class.isAssignableFrom(clazz)) {
|
||||
result.add((IGuitarDiagramAnalyzer) clazz.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
}
|
||||
|
||||
List<IGuitarDiagramAnalyzer> result = getIndexedInstances(IGuitarDiagramAnalyzer.class);
|
||||
|
||||
if (result.isEmpty()) {
|
||||
return null;
|
||||
|
||||
@@ -611,7 +611,11 @@
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Improve performance of 'Project Explorer' pane</description>
|
||||
<description>Improved performance of application initialization</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Improved performance of 'Project Explorer' pane</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
|
||||
<dependencies>
|
||||
<!-- Internal module dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-processor</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-core</artifactId>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>6.8.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>diylc-processor</artifactId>
|
||||
<name>DIYLC Annotation Processor</name>
|
||||
<description>Build-time indexer that lists the implementations of @Indexed types under META-INF/services</description>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- the processor cannot run while it is itself being compiled -->
|
||||
<proc>none</proc>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.processor;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.StandardLocation;
|
||||
|
||||
/**
|
||||
* Lists every concrete class of the module being compiled under
|
||||
* {@code META-INF/services/<type>} for each of its supertypes that carries
|
||||
* {@code org.diylc.core.annotations.Indexed}. The application reads these files at startup instead
|
||||
* of scanning the classpath.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
@SupportedAnnotationTypes("*")
|
||||
public class ServiceIndexProcessor extends AbstractProcessor {
|
||||
|
||||
private static final String INDEXED_ANNOTATION = "org.diylc.core.annotations.Indexed";
|
||||
private static final String SERVICES_DIR = "META-INF/services/";
|
||||
|
||||
private final Map<String, Set<String>> index = new TreeMap<String, Set<String>>();
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latestSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
if (roundEnv.processingOver()) {
|
||||
writeIndex();
|
||||
} else {
|
||||
for (Element element : roundEnv.getRootElements()) {
|
||||
collect(element);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void collect(Element element) {
|
||||
if (!(element instanceof TypeElement)) {
|
||||
return;
|
||||
}
|
||||
TypeElement type = (TypeElement) element;
|
||||
if (isInstantiable(type)) {
|
||||
String className = processingEnv.getElementUtils().getBinaryName(type).toString();
|
||||
for (String service : findIndexedSupertypes(type)) {
|
||||
index.computeIfAbsent(service, k -> new TreeSet<String>()).add(className);
|
||||
}
|
||||
}
|
||||
for (Element enclosed : type.getEnclosedElements()) {
|
||||
if (enclosed.getModifiers().contains(Modifier.STATIC)) {
|
||||
collect(enclosed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInstantiable(TypeElement type) {
|
||||
return type.getKind() == ElementKind.CLASS && !type.getModifiers().contains(Modifier.ABSTRACT);
|
||||
}
|
||||
|
||||
private Set<String> findIndexedSupertypes(TypeElement type) {
|
||||
Set<String> result = new HashSet<String>();
|
||||
Set<String> visited = new HashSet<String>();
|
||||
Deque<TypeMirror> pending = new ArrayDeque<TypeMirror>();
|
||||
pending.add(type.asType());
|
||||
while (!pending.isEmpty()) {
|
||||
for (TypeMirror supertype : processingEnv.getTypeUtils().directSupertypes(pending.poll())) {
|
||||
if (supertype.getKind() != TypeKind.DECLARED) {
|
||||
continue;
|
||||
}
|
||||
TypeElement supertypeElement = (TypeElement) ((DeclaredType) supertype).asElement();
|
||||
String name = processingEnv.getElementUtils().getBinaryName(supertypeElement).toString();
|
||||
if (!visited.add(name)) {
|
||||
continue;
|
||||
}
|
||||
if (isIndexed(supertypeElement)) {
|
||||
result.add(name);
|
||||
}
|
||||
pending.add(supertype);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isIndexed(TypeElement type) {
|
||||
for (AnnotationMirror annotation : type.getAnnotationMirrors()) {
|
||||
TypeElement annotationType = (TypeElement) annotation.getAnnotationType().asElement();
|
||||
if (annotationType.getQualifiedName().contentEquals(INDEXED_ANNOTATION)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void writeIndex() {
|
||||
for (Map.Entry<String, Set<String>> entry : index.entrySet()) {
|
||||
String path = SERVICES_DIR + entry.getKey();
|
||||
Set<String> classNames = new TreeSet<String>(entry.getValue());
|
||||
// an incremental build (e.g. in the IDE) compiles only the changed classes, so carry over
|
||||
// the entries from the previous build that still qualify
|
||||
classNames.addAll(readPreviousEntries(path, entry.getKey()));
|
||||
try {
|
||||
FileObject file =
|
||||
processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", path);
|
||||
try (Writer writer =
|
||||
new OutputStreamWriter(file.openOutputStream(), StandardCharsets.UTF_8)) {
|
||||
for (String className : classNames) {
|
||||
writer.write(className);
|
||||
writer.write('\n');
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
|
||||
"Could not write " + path + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> readPreviousEntries(String path, String service) {
|
||||
Set<String> result = new TreeSet<String>();
|
||||
try {
|
||||
FileObject file =
|
||||
processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", path);
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(file.openInputStream(), StandardCharsets.UTF_8))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (!line.isEmpty() && stillQualifies(line, service)) {
|
||||
result.add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// no previous build output
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean stillQualifies(String className, String service) {
|
||||
TypeElement type = processingEnv.getElementUtils().getTypeElement(className.replace('$', '.'));
|
||||
return type != null && isInstantiable(type) && findIndexedSupertypes(type).contains(service);
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.diylc.processor.ServiceIndexProcessor
|
||||
@@ -20,6 +20,10 @@
|
||||
|
||||
<dependencies>
|
||||
<!-- Internal module dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-processor</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-core</artifactId>
|
||||
|
||||
+21
-1
@@ -90,6 +90,8 @@ class ComponentTabbedPane extends JTabbedPane {
|
||||
private List<String> blocks;
|
||||
|
||||
private final Map<String, Component> categoryPanels = new HashMap<String, Component>();
|
||||
private final Map<Component, List<ComponentType>> unpopulatedPanels =
|
||||
new HashMap<Component, List<ComponentType>>();
|
||||
private boolean refreshing = false;
|
||||
|
||||
public ComponentTabbedPane(IPlugInPort plugInPort, ISwingUI swingUI) {
|
||||
@@ -111,6 +113,7 @@ class ComponentTabbedPane extends JTabbedPane {
|
||||
if (lastSelectedTab >= 0 && lastSelectedTab < getTabCount()) {
|
||||
setSelectedIndex(lastSelectedTab);
|
||||
}
|
||||
populateTab(getSelectedComponent());
|
||||
|
||||
addChangeListener(new ChangeListener() {
|
||||
|
||||
@@ -119,6 +122,7 @@ class ComponentTabbedPane extends JTabbedPane {
|
||||
if (refreshing) {
|
||||
return;
|
||||
}
|
||||
populateTab(getSelectedComponent());
|
||||
ConfigurationManager.getInstance().writeValue(LAST_SELECTED_TAB, getSelectedIndex());
|
||||
ComponentTabbedPane.this.plugInPort.setNewComponentTypeSlot(null, null, null, false);
|
||||
// Refresh recent components if needed
|
||||
@@ -157,6 +161,11 @@ class ComponentTabbedPane extends JTabbedPane {
|
||||
}
|
||||
addTab(category, panel);
|
||||
}
|
||||
// the tabbed pane takes its height from the tallest tab, so keep one category populated
|
||||
// even while a sparse tab like Favorites is selected
|
||||
if (getTabCount() > 3) {
|
||||
populateTab(getComponentAt(3));
|
||||
}
|
||||
|
||||
if (selectedTitle != null) {
|
||||
for (int i = 0; i < getTabCount(); i++) {
|
||||
@@ -175,6 +184,7 @@ class ComponentTabbedPane extends JTabbedPane {
|
||||
} else if (getTabCount() > 0) {
|
||||
setSelectedIndex(0);
|
||||
}
|
||||
populateTab(getSelectedComponent());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -238,11 +248,21 @@ class ComponentTabbedPane extends JTabbedPane {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
|
||||
panel.setOpaque(false);
|
||||
panel.add(createComponentPanel(componentTypes), BorderLayout.CENTER);
|
||||
// buttons are added by populateTab() when the tab is first shown, as creating a button draws
|
||||
// its component icon
|
||||
unpopulatedPanels.put(panel, componentTypes);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
private void populateTab(Component panel) {
|
||||
List<ComponentType> componentTypes = unpopulatedPanels.remove(panel);
|
||||
if (componentTypes != null) {
|
||||
((JPanel) panel).add(createComponentPanel(componentTypes), BorderLayout.CENTER);
|
||||
panel.revalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public Container getRecentToolbar() {
|
||||
if (recentToolbar == null) {
|
||||
recentToolbar = new Container();
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<description>A free, open-source, cross-platform tool for drawing circuit layouts</description>
|
||||
|
||||
<modules>
|
||||
<module>diylc-processor</module>
|
||||
<module>diylc-core</module>
|
||||
<module>diylc-library</module>
|
||||
<module>diylc-swing</module>
|
||||
@@ -31,6 +32,13 @@
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- Internal module dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-processor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-core</artifactId>
|
||||
@@ -94,7 +102,20 @@
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
<!-- writes the META-INF/services class index; see org.diylc.core.annotations.Indexed -->
|
||||
<annotationProcessors>
|
||||
<annotationProcessor>org.diylc.processor.ServiceIndexProcessor</annotationProcessor>
|
||||
</annotationProcessors>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<!-- test fixtures must not end up in the index -->
|
||||
<id>default-testCompile</id>
|
||||
<configuration>
|
||||
<proc>none</proc>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
||||
Reference in New Issue
Block a user