diff options
| author | 2020-07-06 18:48:36 +0200 | |
|---|---|---|
| committer | 2020-07-06 12:48:36 -0400 | |
| commit | 57af19a99b2c7358d78f102b91482b2073126881 (patch) | |
| tree | c61f16b670a4ee9eed736b38cb7351900587a166 | |
| parent | Fix crash on remapping [T (#261) (diff) | |
| download | enigma-57af19a99b2c7358d78f102b91482b2073126881.tar.gz enigma-57af19a99b2c7358d78f102b91482b2073126881.tar.xz enigma-57af19a99b2c7358d78f102b91482b2073126881.zip | |
Add menu entry to reload jar & mappings from disk (#263)
* Add button to reload jar & mappings from disk
* Disable menu entry when currently loading
* Add menu entry that reloads mappings only
* Remove duplicate user query code
7 files changed, 91 insertions, 38 deletions
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java index ec68d0df..8f105058 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java | |||
| @@ -393,7 +393,6 @@ public class Gui { | |||
| 393 | } | 393 | } |
| 394 | 394 | ||
| 395 | public void onCloseJar() { | 395 | public void onCloseJar() { |
| 396 | |||
| 397 | // update gui | 396 | // update gui |
| 398 | this.frame.setTitle(Enigma.NAME); | 397 | this.frame.setTitle(Enigma.NAME); |
| 399 | setObfClasses(null); | 398 | setObfClasses(null); |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java index 124ad07e..2f5e5e1e 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java | |||
| @@ -178,6 +178,28 @@ public class GuiController implements ClientPacketHandler { | |||
| 178 | chp.invalidateMapped(); | 178 | chp.invalidateMapped(); |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | public void reloadAll() { | ||
| 182 | Path jarPath = this.project.getJarPath(); | ||
| 183 | MappingFormat loadedMappingFormat = this.loadedMappingFormat; | ||
| 184 | Path loadedMappingPath = this.loadedMappingPath; | ||
| 185 | if (jarPath != null) { | ||
| 186 | this.closeJar(); | ||
| 187 | CompletableFuture<Void> f = this.openJar(jarPath); | ||
| 188 | if (loadedMappingFormat != null && loadedMappingPath != null) { | ||
| 189 | f.whenComplete((v, t) -> this.openMappings(loadedMappingFormat, loadedMappingPath)); | ||
| 190 | } | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | public void reloadMappings() { | ||
| 195 | MappingFormat loadedMappingFormat = this.loadedMappingFormat; | ||
| 196 | Path loadedMappingPath = this.loadedMappingPath; | ||
| 197 | if (loadedMappingFormat != null && loadedMappingPath != null) { | ||
| 198 | this.closeMappings(); | ||
| 199 | this.openMappings(loadedMappingFormat, loadedMappingPath); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 181 | public CompletableFuture<Void> dropMappings() { | 203 | public CompletableFuture<Void> dropMappings() { |
| 182 | if (project == null) return CompletableFuture.completedFuture(null); | 204 | if (project == null) return CompletableFuture.completedFuture(null); |
| 183 | 205 | ||
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java index 768bc410..d6c60e04 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java | |||
| @@ -40,6 +40,8 @@ public class MenuBar { | |||
| 40 | private final JMenu saveMappingsAsMenu = new JMenu(I18n.translate("menu.file.mappings.save_as")); | 40 | private final JMenu saveMappingsAsMenu = new JMenu(I18n.translate("menu.file.mappings.save_as")); |
| 41 | private final JMenuItem closeMappingsItem = new JMenuItem(I18n.translate("menu.file.mappings.close")); | 41 | private final JMenuItem closeMappingsItem = new JMenuItem(I18n.translate("menu.file.mappings.close")); |
| 42 | private final JMenuItem dropMappingsItem = new JMenuItem(I18n.translate("menu.file.mappings.drop")); | 42 | private final JMenuItem dropMappingsItem = new JMenuItem(I18n.translate("menu.file.mappings.drop")); |
| 43 | private final JMenuItem reloadMappingsItem = new JMenuItem(I18n.translate("menu.file.reload_mappings")); | ||
| 44 | private final JMenuItem reloadAllItem = new JMenuItem(I18n.translate("menu.file.reload_all")); | ||
| 43 | private final JMenuItem exportSourceItem = new JMenuItem(I18n.translate("menu.file.export.source")); | 45 | private final JMenuItem exportSourceItem = new JMenuItem(I18n.translate("menu.file.export.source")); |
| 44 | private final JMenuItem exportJarItem = new JMenuItem(I18n.translate("menu.file.export.jar")); | 46 | private final JMenuItem exportJarItem = new JMenuItem(I18n.translate("menu.file.export.jar")); |
| 45 | private final JMenuItem statsItem = new JMenuItem(I18n.translate("menu.file.stats")); | 47 | private final JMenuItem statsItem = new JMenuItem(I18n.translate("menu.file.stats")); |
| @@ -83,6 +85,9 @@ public class MenuBar { | |||
| 83 | this.fileMenu.add(this.closeMappingsItem); | 85 | this.fileMenu.add(this.closeMappingsItem); |
| 84 | this.fileMenu.add(this.dropMappingsItem); | 86 | this.fileMenu.add(this.dropMappingsItem); |
| 85 | this.fileMenu.addSeparator(); | 87 | this.fileMenu.addSeparator(); |
| 88 | this.fileMenu.add(this.reloadMappingsItem); | ||
| 89 | this.fileMenu.add(this.reloadAllItem); | ||
| 90 | this.fileMenu.addSeparator(); | ||
| 86 | this.fileMenu.add(this.exportSourceItem); | 91 | this.fileMenu.add(this.exportSourceItem); |
| 87 | this.fileMenu.add(this.exportJarItem); | 92 | this.fileMenu.add(this.exportJarItem); |
| 88 | this.fileMenu.addSeparator(); | 93 | this.fileMenu.addSeparator(); |
| @@ -117,6 +122,8 @@ public class MenuBar { | |||
| 117 | this.saveMappingsItem.addActionListener(_e -> this.onSaveMappingsClicked()); | 122 | this.saveMappingsItem.addActionListener(_e -> this.onSaveMappingsClicked()); |
| 118 | this.closeMappingsItem.addActionListener(_e -> this.onCloseMappingsClicked()); | 123 | this.closeMappingsItem.addActionListener(_e -> this.onCloseMappingsClicked()); |
| 119 | this.dropMappingsItem.addActionListener(_e -> this.gui.getController().dropMappings()); | 124 | this.dropMappingsItem.addActionListener(_e -> this.gui.getController().dropMappings()); |
| 125 | this.reloadMappingsItem.addActionListener(_e -> this.onReloadMappingsClicked()); | ||
| 126 | this.reloadAllItem.addActionListener(_e -> this.onReloadAllClicked()); | ||
| 120 | this.exportSourceItem.addActionListener(_e -> this.onExportSourceClicked()); | 127 | this.exportSourceItem.addActionListener(_e -> this.onExportSourceClicked()); |
| 121 | this.exportJarItem.addActionListener(_e -> this.onExportJarClicked()); | 128 | this.exportJarItem.addActionListener(_e -> this.onExportJarClicked()); |
| 122 | this.statsItem.addActionListener(_e -> StatsDialog.show(this.gui)); | 129 | this.statsItem.addActionListener(_e -> StatsDialog.show(this.gui)); |
| @@ -143,6 +150,8 @@ public class MenuBar { | |||
| 143 | this.saveMappingsItem.setEnabled(jarOpen && this.gui.enigmaMappingsFileChooser.getSelectedFile() != null && connectionState != ConnectionState.CONNECTED); | 150 | this.saveMappingsItem.setEnabled(jarOpen && this.gui.enigmaMappingsFileChooser.getSelectedFile() != null && connectionState != ConnectionState.CONNECTED); |
| 144 | this.saveMappingsAsMenu.setEnabled(jarOpen); | 151 | this.saveMappingsAsMenu.setEnabled(jarOpen); |
| 145 | this.closeMappingsItem.setEnabled(jarOpen); | 152 | this.closeMappingsItem.setEnabled(jarOpen); |
| 153 | this.reloadMappingsItem.setEnabled(jarOpen); | ||
| 154 | this.reloadAllItem.setEnabled(jarOpen); | ||
| 146 | this.exportSourceItem.setEnabled(jarOpen); | 155 | this.exportSourceItem.setEnabled(jarOpen); |
| 147 | this.exportJarItem.setEnabled(jarOpen); | 156 | this.exportJarItem.setEnabled(jarOpen); |
| 148 | this.statsItem.setEnabled(jarOpen); | 157 | this.statsItem.setEnabled(jarOpen); |
| @@ -169,21 +178,33 @@ public class MenuBar { | |||
| 169 | this.gui.getController().saveMappings(this.gui.enigmaMappingsFileChooser.getSelectedFile().toPath()); | 178 | this.gui.getController().saveMappings(this.gui.enigmaMappingsFileChooser.getSelectedFile().toPath()); |
| 170 | } | 179 | } |
| 171 | 180 | ||
| 172 | private void onCloseMappingsClicked() { | 181 | private void openMappingsDiscardPrompt(Runnable then) { |
| 173 | if (this.gui.getController().isDirty()) { | 182 | if (this.gui.getController().isDirty()) { |
| 174 | this.gui.showDiscardDiag((response -> { | 183 | this.gui.showDiscardDiag((response -> { |
| 175 | if (response == JOptionPane.YES_OPTION) { | 184 | if (response == JOptionPane.YES_OPTION) { |
| 176 | this.gui.saveMapping(); | 185 | this.gui.saveMapping(); |
| 177 | this.gui.getController().closeMappings(); | 186 | then.run(); |
| 178 | } else if (response == JOptionPane.NO_OPTION) | 187 | } else if (response == JOptionPane.NO_OPTION) |
| 179 | this.gui.getController().closeMappings(); | 188 | then.run(); |
| 180 | return null; | 189 | return null; |
| 181 | }), I18n.translate("prompt.close.save"), I18n.translate("prompt.close.discard"), I18n.translate("prompt.close.cancel")); | 190 | }), I18n.translate("prompt.close.save"), I18n.translate("prompt.close.discard"), I18n.translate("prompt.close.cancel")); |
| 182 | } else { | 191 | } else { |
| 183 | this.gui.getController().closeMappings(); | 192 | then.run(); |
| 184 | } | 193 | } |
| 185 | } | 194 | } |
| 186 | 195 | ||
| 196 | private void onCloseMappingsClicked() { | ||
| 197 | openMappingsDiscardPrompt(() -> this.gui.getController().closeMappings()); | ||
| 198 | } | ||
| 199 | |||
| 200 | private void onReloadMappingsClicked() { | ||
| 201 | openMappingsDiscardPrompt(() -> this.gui.getController().reloadMappings()); | ||
| 202 | } | ||
| 203 | |||
| 204 | private void onReloadAllClicked() { | ||
| 205 | openMappingsDiscardPrompt(() -> this.gui.getController().reloadAll()); | ||
| 206 | } | ||
| 207 | |||
| 187 | private void onExportSourceClicked() { | 208 | private void onExportSourceClicked() { |
| 188 | if (this.gui.exportSourceFileChooser.showSaveDialog(this.gui.getFrame()) == JFileChooser.APPROVE_OPTION) { | 209 | if (this.gui.exportSourceFileChooser.showSaveDialog(this.gui.getFrame()) == JFileChooser.APPROVE_OPTION) { |
| 189 | this.gui.getController().exportSource(this.gui.exportSourceFileChooser.getSelectedFile().toPath()); | 210 | this.gui.getController().exportSource(this.gui.exportSourceFileChooser.getSelectedFile().toPath()); |
diff --git a/enigma/src/main/java/cuchaz/enigma/Enigma.java b/enigma/src/main/java/cuchaz/enigma/Enigma.java index 2e9be34f..d100a75a 100644 --- a/enigma/src/main/java/cuchaz/enigma/Enigma.java +++ b/enigma/src/main/java/cuchaz/enigma/Enigma.java | |||
| @@ -11,8 +11,16 @@ | |||
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import java.io.IOException; | ||
| 15 | import java.nio.file.Path; | ||
| 16 | import java.util.List; | ||
| 17 | import java.util.ServiceLoader; | ||
| 18 | import java.util.Set; | ||
| 19 | |||
| 14 | import com.google.common.base.Preconditions; | 20 | import com.google.common.base.Preconditions; |
| 15 | import com.google.common.collect.ImmutableListMultimap; | 21 | import com.google.common.collect.ImmutableListMultimap; |
| 22 | import org.objectweb.asm.Opcodes; | ||
| 23 | |||
| 16 | import cuchaz.enigma.analysis.index.JarIndex; | 24 | import cuchaz.enigma.analysis.index.JarIndex; |
| 17 | import cuchaz.enigma.api.EnigmaPlugin; | 25 | import cuchaz.enigma.api.EnigmaPlugin; |
| 18 | import cuchaz.enigma.api.EnigmaPluginContext; | 26 | import cuchaz.enigma.api.EnigmaPluginContext; |
| @@ -25,13 +33,6 @@ import cuchaz.enigma.classprovider.ClassProvider; | |||
| 25 | import cuchaz.enigma.classprovider.CombiningClassProvider; | 33 | import cuchaz.enigma.classprovider.CombiningClassProvider; |
| 26 | import cuchaz.enigma.classprovider.JarClassProvider; | 34 | import cuchaz.enigma.classprovider.JarClassProvider; |
| 27 | import cuchaz.enigma.utils.Utils; | 35 | import cuchaz.enigma.utils.Utils; |
| 28 | import org.objectweb.asm.Opcodes; | ||
| 29 | |||
| 30 | import java.io.IOException; | ||
| 31 | import java.nio.file.Path; | ||
| 32 | import java.util.List; | ||
| 33 | import java.util.ServiceLoader; | ||
| 34 | import java.util.Set; | ||
| 35 | 36 | ||
| 36 | public class Enigma { | 37 | public class Enigma { |
| 37 | public static final String NAME = "Enigma"; | 38 | public static final String NAME = "Enigma"; |
| @@ -64,7 +65,7 @@ public class Enigma { | |||
| 64 | index.indexJar(scope, classProvider, progress); | 65 | index.indexJar(scope, classProvider, progress); |
| 65 | services.get(JarIndexerService.TYPE).forEach(indexer -> indexer.acceptJar(scope, classProvider, index)); | 66 | services.get(JarIndexerService.TYPE).forEach(indexer -> indexer.acceptJar(scope, classProvider, index)); |
| 66 | 67 | ||
| 67 | return new EnigmaProject(this, classProvider, index, Utils.zipSha1(path)); | 68 | return new EnigmaProject(this, path, classProvider, index, Utils.zipSha1(path)); |
| 68 | } | 69 | } |
| 69 | 70 | ||
| 70 | public EnigmaProfile getProfile() { | 71 | public EnigmaProfile getProfile() { |
diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java index 76413ab7..2abd39c1 100644 --- a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java +++ b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java | |||
| @@ -1,7 +1,26 @@ | |||
| 1 | package cuchaz.enigma; | 1 | package cuchaz.enigma; |
| 2 | 2 | ||
| 3 | import java.io.BufferedWriter; | ||
| 4 | import java.io.IOException; | ||
| 5 | import java.io.PrintWriter; | ||
| 6 | import java.io.StringWriter; | ||
| 7 | import java.nio.file.Files; | ||
| 8 | import java.nio.file.Path; | ||
| 9 | import java.util.Collection; | ||
| 10 | import java.util.List; | ||
| 11 | import java.util.Map; | ||
| 12 | import java.util.Objects; | ||
| 13 | import java.util.concurrent.atomic.AtomicInteger; | ||
| 14 | import java.util.jar.JarEntry; | ||
| 15 | import java.util.jar.JarOutputStream; | ||
| 16 | import java.util.stream.Collectors; | ||
| 17 | import java.util.stream.Stream; | ||
| 18 | |||
| 3 | import com.google.common.base.Functions; | 19 | import com.google.common.base.Functions; |
| 4 | import com.google.common.base.Preconditions; | 20 | import com.google.common.base.Preconditions; |
| 21 | import org.objectweb.asm.ClassWriter; | ||
| 22 | import org.objectweb.asm.tree.ClassNode; | ||
| 23 | |||
| 5 | import cuchaz.enigma.analysis.EntryReference; | 24 | import cuchaz.enigma.analysis.EntryReference; |
| 6 | import cuchaz.enigma.analysis.index.JarIndex; | 25 | import cuchaz.enigma.analysis.index.JarIndex; |
| 7 | import cuchaz.enigma.api.service.NameProposalService; | 26 | import cuchaz.enigma.api.service.NameProposalService; |
| @@ -23,37 +42,21 @@ import cuchaz.enigma.translation.representation.entry.Entry; | |||
| 23 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | 42 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; |
| 24 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 43 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 25 | import cuchaz.enigma.utils.I18n; | 44 | import cuchaz.enigma.utils.I18n; |
| 26 | import org.objectweb.asm.ClassWriter; | ||
| 27 | import org.objectweb.asm.tree.ClassNode; | ||
| 28 | |||
| 29 | import java.io.BufferedWriter; | ||
| 30 | import java.io.IOException; | ||
| 31 | import java.io.PrintWriter; | ||
| 32 | import java.io.StringWriter; | ||
| 33 | import java.nio.file.Files; | ||
| 34 | import java.nio.file.Path; | ||
| 35 | import java.util.Collection; | ||
| 36 | import java.util.List; | ||
| 37 | import java.util.Map; | ||
| 38 | import java.util.Objects; | ||
| 39 | import java.util.concurrent.atomic.AtomicInteger; | ||
| 40 | import java.util.jar.JarEntry; | ||
| 41 | import java.util.jar.JarOutputStream; | ||
| 42 | import java.util.stream.Collectors; | ||
| 43 | import java.util.stream.Stream; | ||
| 44 | 45 | ||
| 45 | public class EnigmaProject { | 46 | public class EnigmaProject { |
| 46 | private final Enigma enigma; | 47 | private final Enigma enigma; |
| 47 | 48 | ||
| 49 | private final Path jarPath; | ||
| 48 | private final ClassProvider classProvider; | 50 | private final ClassProvider classProvider; |
| 49 | private final JarIndex jarIndex; | 51 | private final JarIndex jarIndex; |
| 50 | private final byte[] jarChecksum; | 52 | private final byte[] jarChecksum; |
| 51 | 53 | ||
| 52 | private EntryRemapper mapper; | 54 | private EntryRemapper mapper; |
| 53 | 55 | ||
| 54 | public EnigmaProject(Enigma enigma, ClassProvider classProvider, JarIndex jarIndex, byte[] jarChecksum) { | 56 | public EnigmaProject(Enigma enigma, Path jarPath, ClassProvider classProvider, JarIndex jarIndex, byte[] jarChecksum) { |
| 55 | Preconditions.checkArgument(jarChecksum.length == 20); | 57 | Preconditions.checkArgument(jarChecksum.length == 20); |
| 56 | this.enigma = enigma; | 58 | this.enigma = enigma; |
| 59 | this.jarPath = jarPath; | ||
| 57 | this.classProvider = classProvider; | 60 | this.classProvider = classProvider; |
| 58 | this.jarIndex = jarIndex; | 61 | this.jarIndex = jarIndex; |
| 59 | this.jarChecksum = jarChecksum; | 62 | this.jarChecksum = jarChecksum; |
| @@ -73,6 +76,10 @@ public class EnigmaProject { | |||
| 73 | return enigma; | 76 | return enigma; |
| 74 | } | 77 | } |
| 75 | 78 | ||
| 79 | public Path getJarPath() { | ||
| 80 | return jarPath; | ||
| 81 | } | ||
| 82 | |||
| 76 | public ClassProvider getClassProvider() { | 83 | public ClassProvider getClassProvider() { |
| 77 | return classProvider; | 84 | return classProvider; |
| 78 | } | 85 | } |
diff --git a/enigma/src/main/resources/lang/en_us.json b/enigma/src/main/resources/lang/en_us.json index a98caa9d..debe9d15 100644 --- a/enigma/src/main/resources/lang/en_us.json +++ b/enigma/src/main/resources/lang/en_us.json | |||
| @@ -23,6 +23,8 @@ | |||
| 23 | "menu.file.mappings.save_as": "Save Mappings As...", | 23 | "menu.file.mappings.save_as": "Save Mappings As...", |
| 24 | "menu.file.mappings.close": "Close Mappings", | 24 | "menu.file.mappings.close": "Close Mappings", |
| 25 | "menu.file.mappings.drop": "Drop Invalid Mappings", | 25 | "menu.file.mappings.drop": "Drop Invalid Mappings", |
| 26 | "menu.file.reload_mappings": "Reload Mappings", | ||
| 27 | "menu.file.reload_all": "Reload Jar/Mappings", | ||
| 26 | "menu.file.export.source": "Export Source...", | 28 | "menu.file.export.source": "Export Source...", |
| 27 | "menu.file.export.jar": "Export Jar...", | 29 | "menu.file.export.jar": "Export Jar...", |
| 28 | "menu.file.stats": "Mapping Stats...", | 30 | "menu.file.stats": "Mapping Stats...", |
diff --git a/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java b/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java index 6daa2931..b3d35175 100644 --- a/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java +++ b/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java | |||
| @@ -11,16 +11,17 @@ | |||
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import java.nio.file.Files; | ||
| 15 | import java.nio.file.Path; | ||
| 16 | import java.nio.file.Paths; | ||
| 17 | |||
| 18 | import org.junit.BeforeClass; | ||
| 19 | import org.junit.Test; | ||
| 20 | |||
| 14 | import cuchaz.enigma.classprovider.ClasspathClassProvider; | 21 | import cuchaz.enigma.classprovider.ClasspathClassProvider; |
| 15 | import cuchaz.enigma.source.Decompiler; | 22 | import cuchaz.enigma.source.Decompiler; |
| 16 | import cuchaz.enigma.source.Decompilers; | 23 | import cuchaz.enigma.source.Decompilers; |
| 17 | import cuchaz.enigma.source.SourceSettings; | 24 | import cuchaz.enigma.source.SourceSettings; |
| 18 | import org.junit.BeforeClass; | ||
| 19 | import org.junit.Test; | ||
| 20 | |||
| 21 | import java.nio.file.Files; | ||
| 22 | import java.nio.file.Path; | ||
| 23 | import java.nio.file.Paths; | ||
| 24 | 25 | ||
| 25 | import static cuchaz.enigma.TestEntryFactory.newClass; | 26 | import static cuchaz.enigma.TestEntryFactory.newClass; |
| 26 | import static org.hamcrest.MatcherAssert.assertThat; | 27 | import static org.hamcrest.MatcherAssert.assertThat; |