Why am I getting this compiler error (using enum as singleton)? - java

I have the following class, which encapsulates some test data. I need only one instance of it, so I create an enum.
public enum ErnstReuterPlatzBuildings {
INSTANCE; // Compiler error occurs here
private final Map<String, IBuilding> buildingsByIds;
ErnstReuterPlatzBuildings() throws ParserConfigurationException,
SAXException, XPathExpressionException, IOException {
this.buildingsByIds = composeBuildingsByIds(
getBuildings(ErnstReuterPlatzBuildings.class)
);
}
public Map<String, IBuilding> getBuildingsByIds() {
return buildingsByIds;
}
public static Document readErnstReuterPlatzData(final Class clazz)
throws ParserConfigurationException, SAXException, IOException {
final InputStream stream =
clazz.getClassLoader()
.getResourceAsStream("mc/ernstReuterPlatz/map.osm");
final DocumentBuilderFactory dbfac =
DocumentBuilderFactory.newInstance();
final DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
return docBuilder.parse(stream);
}
private Map<String, IBuilding> composeBuildingsByIds(
final Set<IBuilding> buildings) {
final Map<String,IBuilding> buildingsByIds = new HashMap<>();
for (final IBuilding building : buildings) {
buildingsByIds.put(building.getWayId(), building);
}
return buildingsByIds;
}
private Set<IBuilding> getBuildings(final Class clazz)
throws ParserConfigurationException, SAXException, IOException,
XPathExpressionException {
final Document doc = readErnstReuterPlatzData(clazz);
final PointsReader pointsReader = new PointsReader(doc);
pointsReader.init();
final BuildingExtractor testObject =
new BuildingExtractor(pointsReader);
return testObject.extractBuildings(doc);
}
}
At the declaration of its only element, INSTANCE; I get the following compiler error in IntelliJ Idea:
Error:(22, 5) java: unreported exception javax.xml.parsers.ParserConfigurationException; must be caught or declared to be thrown
How can I fix it, given that it occurs at the line, where the element is defined, not a method?

How can I fix it, given that it occurs at the line, where the element is defined, not a method?
Under the hood Java creates an instance INSTANCE by calling the constructor. The code on the declaration line looks similar to this:
public static final INSTANCE = new ErnstReuterPlatzBuildings();
That's why the error is coming from that line.
As far as I know, there is no way to fix this by allowing the user to catch a checked exception, because INSTANCE is initialized in a context outside of any method call.
You can work around this issue by catching the exception yourself, and wrapping it in an unchecked RuntimeException of an appropriate type or even an ExceptionInInitializerError:
ErnstReuterPlatzBuildings() {
try {
this.buildingsByIds = composeBuildingsByIds(
getBuildings(ErnstReuterPlatzBuildings.class)
);
} catch (ParserConfigurationException pce) {
throw new ExceptionInInitializerError(pce);
} catch (SAXException sxe) {
throw new ExceptionInInitializerError(sxe);
} catch (XPathExpressionException xpe) {
throw new ExceptionInInitializerError(xpe);
} catch (IOException ioe) {
throw new ExceptionInInitializerError(ioe);
}
}

Related

Throwing IOException from main() in Lambda-expression [duplicate]

This question already has answers here:
How can I throw CHECKED exceptions from inside Java 8 lambdas/streams?
(18 answers)
Closed 4 years ago.
I have a task to "move" my throws Exception from main() to lambda-expression. That means that when exception occurs in Lambda, the program uses throws from main. The problem is that I can't create any other interface which could automatically do that, because my teacher said to use only interface from java.util.Function and I've been looking in the internet, but mostly there are answers like "create new interface".
public static void main(String[] args) throws IOException {
Function<String, List<String>> flines = (String x) -> {
Stream<String> streamString = Files.lines(Paths.get(x)); //Should throw Exception from main if IOException
List<String> tmp = streamString.collect(Collectors.toList());
return tmp;
};
You can only throw a unchecked exception as Function doesn't declare any checked exception in the signature of its functional interface.
So you can only explicitly throw a RuntimeException (and its subclasses) instances from the lambda body such as :
Function<String, List<String>> flines = (String x) -> {
try{
Stream<String> streamString = Files.lines(Paths.get(x));
List<String> tmp = streamString.collect(Collectors.toList());
return tmp;
}
catch (IOException e){
throw new RuntimeIOException(e);
}
};
But declaring throws IOException in the main() method is so helpless as it will never be thrown it but if you catch the runtime exception in the Function client and that then you re-throw a IOException. But that is a lot of things for almost nothing.
You can catch the IOException inside the lambda expression, wrap it in a RuntimeException, catch that exception in the main, extract the wrapped IOException and throw it:
public static void main(String[] args) throws IOException
{
Function<String, List<String>> flines = (String x) -> {
List<String> tmp = null;
try {
Stream<String> streamString = Files.lines(Paths.get(x));
tmp = streamString.collect(Collectors.toList());
} catch (IOException ioEx) {
throw new RuntimeException (ioEx);
}
return tmp;
};
try {
List<String> lines = flines.apply ("filename.txt");
}
catch (RuntimeException runEx) {
if (runEx.getCause () instanceof IOException) {
throw (IOException) runEx.getCause ();
}
}
}

JUnit expected exception not working as expected

i am trying to test a private method inside an ActionListener. The method should throw an exception if an invalid url is passed:
Heres the code of my test:
#Rule
public ExpectedException expectedException = ExpectedException.none();
Map<JLabel, JTextField> inputs;
ActionListener listener;
AddStationWindow window;
ArrayList<Station> stationsToDelete;
#Before
public void setUp() throws IllegalAccessException, NoSuchFieldException,
InstantiationException, SQLException, ClassNotFoundException {
inputs = new HashMap<JLabel, JTextField>();
window = new AddStationWindow();
stationsToDelete = new ArrayList<>();
InitializeH2Database.initialiteDatabase();
}
#Test
public void saveStation() throws NoSuchFieldException,
IllegalAccessException, MalformedURLException, NoSuchMethodException,
InvocationTargetException {
Field f = window.getClass().getDeclaredField("inputElements");
f.setAccessible(true);
LinkedHashMap<JLabel, JTextField> inputs = (LinkedHashMap<JLabel,
JTextField>) f.get(window);
Field f2 = window.getClass().getDeclaredField("save");
f2.setAccessible(true);
JButton saveButton = (JButton) f2.get(window);
inputs.get(window.getInputLabels().get(0)).setText("Testsender");
inputs.get((window.getInputLabels().get(1))).setText("asdasdsa");
ActionListener listener = saveButton.getActionListeners()[0];
Method m = listener.getClass().getDeclaredMethod("saveStation");
m.setAccessible(true);
m.invoke(listener);
expectedException.expect(MalformedURLException.class);
}
#After
public void tearDown() {
stationsToDelete.forEach(s ->
H2DatabaseConnector.getInstance().deleteStation(s));
}
This is the tested method inside the ActionListener:
private boolean saveStation() {
List<JLabel> keys = new ArrayList<>();
for (Map.Entry<JLabel, JTextField> inputElement : inputElements.entrySet()) {
keys.add(inputElement.getKey());
}
String stationName = inputElements.get(keys.get(0)).getText();
String urlString = inputElements.get(keys.get(1)).getText();
URL stationURL = null;
try {
stationURL = new URL(urlString);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(window, "Invalid URL!", "URL
not valid", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
return false;
}
Station s = new Station(stationName, stationURL);
if (checkStation(s)) {
return WebradioPlayer.addStation(s);
}
return false;
}
If i run the test, i can see that the stack tarce shows the malformed url exception with message no protocol: 'asdasdsa', but the test fails.
Can someone explain me why? JUnit version is 4.
You have to set the expected exception before you call the code that actually does throw the exception.
Instead of
#Test
public void saveStation() throws ... {
// code here
expectedException.expect(MalformedURLException.class);
}
you should write the test method as
#Test
public void saveStation() throws ... {
expectedException.expect(MalformedURLException.class);
// code here
}
Additionally, you have to change your method saveStation to not suppress the exception if you actually want to have it thrown. See #Leviand's answer for more details.
Your test is failing because you are expecting an exception to be thrown (you said invalid url exception), but you are wrapping that exception into a try catch, then you are printing the stacktrace.
try {
stationURL = new URL(urlString);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(window, "Invalid URL!", "URL
not valid", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
return false;
}
you have to add the trown declaration in your catch, or not catch it at all, ie:
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(window, "Invalid URL!", "URL
not valid", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
throw new MalformedURLException(e);
}
and add the throw info to your method
private boolean saveStation() throws MalformedURLException{

Unhandled exceptions thrown by a method does not prevent compilation

So I have these two methods in a class:
public String getConsumerKey() throws FileNotFoundException, IOException
{
String consumerKey;
consumerKey = getPropertyValueOrNull(getConfigPath(CONSUMERVALUESCONFIGNAME),"consumer_key");
return consumerKey;
}
private String getPropertyValueOrNull(String path, String key) throws FileNotFoundException, IOException
{
Properties prop = new Properties();
String value = null;
// load a properties file
prop.load(new FileInputStream(path));
value = prop.getProperty(key);
if ( value == null || value.isEmpty())
{
value = null;
}
return value;
}
And I call getCosumerKey() from the main method like this:
public static void main(String[] args)
{
try {
MyClass.getInstance().getConsumerKey();
} catch (IOException e) {
e.printStackTrace();
}
}
When I run this code, there is no problem except that I am getting a FileNotFoundExcpetion. When I tried to add a catch block to handle the FileNotFoundException, I got an error saying that the exception is already handled from the IOException catch block.
Isn't the compiler supposed to prevent me from running the code and why does not compiler let me handle the exception?

What values to put in my properties file to get an IOException while loading?

I am reading a file from its classpath in Java project.
Sample Code:
public static Properties loadPropertyFile(String fileName) {
Properties properties = new Properties();
InputStream inputStream = PropertyReader.class.getClassLoader().getResourceAsStream(fileName);
if (inputStream != null) {
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
} else {
throw new Exception("Property file: [" + fileName + "] not found in the classpath");
}
return properties;
}
It's working fine. I am writing Junit tests for this code. How can I create a scenario for IOException in properties.load(inputStream)?
What values should I put in my properties.file to get IOException?
When you look into the implementation of Properties::load, you find out that the class never throws the exception explicitly. The only way to trigger an IOException would be to hand an InputStream that throws this exception upon invoking the input stream's read method.
Do you have control over the PropertyReader class? One way to emulate this error would be to instrument this class loader to return an errornous InputStream for a given test value of fileName to throw an IOException. Alternatively, you could make the method more flexible by changing the signature to:
public static Properties loadPropertyFile(String fileName) {
return loadPropertyFile(fileName, PropertyReader.class);
}
public static Properties loadPropertyFile(String fileName, ClassLoader cl) {
// your code...
}
with handing a class loader:
class TestLoader extends ClassLoader {
#Override
public InputStream getResourceAsStream() {
return new InputStream() {
#Override
public byte read() throws IOException {
throws new IOException();
}
}
}
}
You cannot add specific characters to the properties file that cause an IOException as the InputStream only reads bytes. Any encoding-realted problem will instead result in an IllegalArgumentException.
Have you considered a mocking framework? Mock the new operator for Properties to return a mock implementation that throws IOException when its load method is called.
mockitio and powermockito will allow you to do this.
One way of forcing the load call to throw IOException is to pass a closed stream. If you can refactor your method to accept a InputStream you can pass a closed stream to the method and check whether it is throwing an exception.
That said, Unit Tests are supposed to cover the code you write. It seems to me you are testing whether load throws an exception if the input stream has an error. Which is superfluous.
I know that this is an old thread, but since I recently ran into the same problem and based on Rafael Winterhalter's answer I came up with this test:
#Test
void testFailLoadProjectFile() throws NoSuchMethodException, SecurityException {
final var method = LogGeneratorComponent.class.getDeclaredMethod("loadProjectProperties", Properties.class);
Assertions.assertTrue(Modifier.isPrivate(method.getModifiers()), "Method is not private.");
method.setAccessible(true);
final var obj = new LogGeneratorComponent();
Assertions.assertThrows(InvocationTargetException.class, () -> method.invoke(obj, new Properties() {
private static final long serialVersionUID = 5663506788956932491L;
#Override
public synchronized void load(#SuppressWarnings("unused") final InputStream is) throws IOException {
throw new IOException("Invalid properties implementation.");
}
}), "An InvocationTargetException should have been thrown, but nothing happened.");
}
And this is my actual method:
private static Properties loadProjectProperties(final Properties properties) {
try (final var is = Thread.currentThread().getContextClassLoader().getResourceAsStream("project.properties")) {
properties.load(is);
return properties;
} catch (final IOException e) {
throw new UncheckedIOException("Error while reading project.properties file.", e);
}
}
Obviously OP can customize it to receive a fileName parameter and make it public in order to have a simpler test.
Empty or Invalid fileName parameter.
pass a blank string as file name

Why is the main method not covered?

main method:
public static void main(String[] args) throws Exception
{
if (args.length != EXPECTED_NUMBER_OF_ARGUMENTS)
{
System.err.println("Usage - java XFRCompiler ConfigXML PackageXML XFR");
}
String configXML = args[0];
String packageXML = args[1];
String xfr = args[2];
AutoConfigCompiler compiler = new AutoConfigCompiler();
compiler.setConfigDocument(loadDocument(configXML));
compiler.setPackageInfoDoc(loadDocument(packageXML));
// compiler.setVisiblityDoc(loadDocument("VisibilityFilter.xml"));
compiler.compileModel(xfr);
}
private static Document loadDocument(String fileName) throws Exception
{
TXDOMParser parser = (TXDOMParser) ParserFactory.makeParser(TXDOMParser.class.getName());
InputSource source = new InputSource(new FileInputStream(fileName));
parser.parse(source);
return parser.getDocument();
}
testcase:
#Test
public void testCompileModel() throws Exception
{
// construct parameters
URL configFile = Thread.currentThread().getContextClassLoader().getResource("Ford_2008_Mustang_Config.xml");
URL packageFile = Thread.currentThread().getContextClassLoader().getResource("Ford_2008_Mustang_Package.xml");
File tmpFile = new File("Ford_2008_Mustang_tmp.xfr");
if(!tmpFile.exists()) {
tmpFile.createNewFile();
}
String[] args = new String[]{configFile.getPath(),packageFile.getPath(),tmpFile.getPath()};
try {
// test main method
XFRCompiler.main(args);
} catch (Exception e) {
assertTrue(true);
}
try {
// test args length is less than 3
XFRCompiler.main(new String[]{"",""});
} catch (Exception e) {
//ignore
}
tmpFile.delete();
}
Coverage outputs displayed as the lines from String configXML = args[0]; in main method
are not covered.
assertTrue(true); is a pointless no-op
Remove the try/catch around the call to XFRCompiler.main(args);, since all it does is swallow excpetions and make debugging harder; most likely you will then see an exception that tells you where the problem is.
There should be a call to fail() after the call to XFRCompiler.main(new String[]{"",""}); since you expect it to throw an exception
Put the two calls in separate test methods.
I'm worried about all those assertTrue(true). If there can't be an exception, then the assert is not necessary. If there is an unexpected exception, then this code will swallow it and you will get the behavior you see right now.
Then, if you expect an exception, you should code like this:
try {
... code that will throw an exception ...
fail("No exception was thrown");
} catch (SpecficTypeOfException e) {
assertEquals("message", e.getMessage());
}
That way, wrong types of exception and the exception message will be checked.
PS: Don't post questions with "urgent". We already help as fast as we can.

Categories