Skip to content

Commit

Permalink
Fix #435. An exception is now thrown when resourceBundle has to be in…
Browse files Browse the repository at this point in the history
…jected but not provided by user (#467)
  • Loading branch information
manuel-mauky authored Jan 26, 2017
1 parent f23b445 commit f65e5e8
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

import de.saxsys.mvvmfx.InjectResourceBundle;

import static de.saxsys.mvvmfx.internal.viewloader.ResourceBundleManager.EMPTY_RESOURCE_BUNDLE;

/**
* This helper class is used to encapsulate the logic for injection of {@link ResourceBundle} into fields annotated with
* {@link InjectResourceBundle} in Views/ViewModels.
Expand All @@ -35,16 +37,14 @@ class ResourceBundleInjector {
* @param target
* the View/ViewModel instance that the ResourceBundle will be injected to. May not be <code>null</code>.
* @param resourceBundle
* the ResourceBundle instance that is used. Can be <code>null</code> if no ResourceBundle was provided
* by the user.
* the ResourceBundle instance that is used.
*/
static void injectResourceBundle(Object target, ResourceBundle resourceBundle) {
final List<Field> fieldsWithAnnotation = ReflectionUtils
.getFieldsWithAnnotation(target, InjectResourceBundle.class);

final boolean notAssignableFieldPresent = fieldsWithAnnotation.stream()
.filter(field -> !field.getType().isAssignableFrom(ResourceBundle.class))
.findAny().isPresent();
.anyMatch(field -> !field.getType().isAssignableFrom(ResourceBundle.class));

if (notAssignableFieldPresent) {
throw new IllegalStateException(
Expand All @@ -53,15 +53,14 @@ static void injectResourceBundle(Object target, ResourceBundle resourceBundle) {
+ "] has at least one field with the annotation @InjectResourceBundle but the field is not of type ResourceBundle.");
}


if (resourceBundle == null) {
// check whether the user has provided any resourceBundle or not
if (resourceBundle == null || resourceBundle.equals(EMPTY_RESOURCE_BUNDLE)) {

if (!fieldsWithAnnotation.isEmpty()) {

final boolean nonOptionalFieldsPresent = fieldsWithAnnotation.stream()
.flatMap(field -> Arrays.stream(field.getAnnotationsByType(InjectResourceBundle.class)))
.filter(annotation -> !annotation.optional())
.findAny().isPresent();
.anyMatch(annotation -> !annotation.optional());

// if all annotated fields are marked as "optional", no exception has to be thrown.
if (nonOptionalFieldsPresent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,16 @@ public class ResourceBundleManager {

ResourceBundleManager() {
}


/**
* Represents an empty ResourceBundle that is used when no actual resourceBundle was provided by the user.
*/
public static final ResourceBundle EMPTY_RESOURCE_BUNDLE = new ListResourceBundle() {
@Override protected Object[][] getContents() {
return new Object[0][];
}
};

public static ResourceBundleManager getInstance() {
return SINGLETON;
}
Expand All @@ -67,7 +76,7 @@ public ResourceBundle getGlobalResourceBundle() {
public ResourceBundle mergeWithGlobal(ResourceBundle resourceBundle) {
if (globalResourceBundle == null) {
if (resourceBundle == null) {
return createEmptyBundle();
return EMPTY_RESOURCE_BUNDLE;
} else {
return new ResourceBundleWrapper(resourceBundle);
}
Expand Down Expand Up @@ -174,13 +183,4 @@ public Set<String> keySet() {
return bundle.keySet();
}
}

private ResourceBundle createEmptyBundle() {
return new ListResourceBundle() {
@Override
protected Object[][] getContents() {
return new Object[0][];
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,154 +17,247 @@

import static de.saxsys.mvvmfx.internal.viewloader.ResourceBundleAssert.assertThat;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Fail.failBecauseExceptionWasNotThrown;

import java.io.StringReader;
import java.util.ListResourceBundle;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

import de.saxsys.mvvmfx.MvvmFX;
import de.saxsys.mvvmfx.internal.viewloader.example.*;
import de.saxsys.mvvmfx.resourcebundle.global.TestView;
import de.saxsys.mvvmfx.resourcebundle.global.TestViewModel;
import de.saxsys.mvvmfx.testingutils.ExceptionUtils;
import de.saxsys.mvvmfx.testingutils.jfxrunner.JfxRunner;
import javafx.scene.layout.VBox;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

import de.saxsys.mvvmfx.FluentViewLoader;
import de.saxsys.mvvmfx.InjectResourceBundle;
import de.saxsys.mvvmfx.JavaView;
import de.saxsys.mvvmfx.ViewTuple;
import de.saxsys.mvvmfx.internal.viewloader.example.TestFxmlViewResourceBundle;
import de.saxsys.mvvmfx.internal.viewloader.example.TestFxmlViewResourceBundleWithoutController;
import de.saxsys.mvvmfx.internal.viewloader.example.TestViewModelWithResourceBundle;

import org.junit.runner.RunWith;

/**
* This test focuses on the handling of {@link ResourceBundle}s.
*
* <p>
* A resourceBundle can be injected into the View with default behaviour of JavaFX. Additionally the user can use the
* mvvmfx annotation {@link InjectResourceBundle} to inject the resourceBundle in the View and in the ViewModel.
*/
@RunWith(JfxRunner.class)
public class FluentViewLoader_ResourceBundle_Test {


private ResourceBundle resourceBundle;

private ResourceBundle globalResourceBundle;

@Before
public void setup() throws Exception {
resourceBundle = new PropertyResourceBundle(new StringReader(""));
resourceBundle = new ListResourceBundle() {
@Override
protected Object[][] getContents() {
return new Object[][] {
{ "key_local1", "value_local1" },
{ "key_local2", "value_local2" },
{ "key_global1", "value_global1" } // overwrite global values
};
}
};

globalResourceBundle = new ListResourceBundle() {
@Override
protected Object[][] getContents() {
return new Object[][] {
{ "key_global1", "value_global1" },
{ "key_global2", "value_global2" }
};
}
};

MvvmFX.setGlobalResourceBundle(null);
}

@After
public void tearDown() {
MvvmFX.setGlobalResourceBundle(null);
}

@Test
public void success_fxml_injectionOfResourceBundles() {
final ViewTuple<TestFxmlViewResourceBundle, TestViewModelWithResourceBundle> viewTuple =
FluentViewLoader
.fxmlView(TestFxmlViewResourceBundle.class)
.resourceBundle(resourceBundle)
.load();

final TestViewModelWithResourceBundle viewModel = viewTuple.getViewModel();
final TestFxmlViewResourceBundle view = viewTuple.getCodeBehind();

assertThat(view.resources).isNotNull().hasSameContent(resourceBundle);
assertThat(view.resourceBundle).isNotNull().hasSameContent(resourceBundle);

assertThat(viewModel.resourceBundle).isNotNull().hasSameContent(resourceBundle);
}

@Test
public void success_fxml_injectionWithExistingViewModel() {
TestViewModelWithResourceBundle viewModel = new TestViewModelWithResourceBundle();

final ViewTuple<TestFxmlViewResourceBundle, TestViewModelWithResourceBundle> viewTuple = FluentViewLoader
.fxmlView(TestFxmlViewResourceBundle.class)
.resourceBundle(resourceBundle)
.viewModel(viewModel)
.load();

assertThat(viewTuple.getViewModel()).isEqualTo(viewModel);
final TestFxmlViewResourceBundle view = viewTuple.getCodeBehind();


assertThat(view.resourceBundle).isNotNull().hasSameContent(resourceBundle);
assertThat(view.resources).isNotNull().hasSameContent(resourceBundle);
assertThat(viewModel.resourceBundle).isNotNull().hasSameContent(resourceBundle);
}


@Test
public void success_fxml_existingCodeBehind() {
TestFxmlViewResourceBundleWithoutController codeBehind = new TestFxmlViewResourceBundleWithoutController();

final ViewTuple<TestFxmlViewResourceBundleWithoutController, TestViewModelWithResourceBundle> viewTuple =
FluentViewLoader
.fxmlView(TestFxmlViewResourceBundleWithoutController.class)
.codeBehind(codeBehind)
.resourceBundle(resourceBundle)
.load();

assertThat(viewTuple.getCodeBehind()).isEqualTo(codeBehind);
final TestViewModelWithResourceBundle viewModel = viewTuple.getViewModel();

assertThat(viewModel.resourceBundle).hasSameContent(resourceBundle);
assertThat(codeBehind.resourceBundle).hasSameContent(resourceBundle);
}

@Test
public void success_fxml_existingCodeBehind_and_existingViewModel() {
TestFxmlViewResourceBundleWithoutController codeBehind = new TestFxmlViewResourceBundleWithoutController();
TestViewModelWithResourceBundle viewModel = new TestViewModelWithResourceBundle();

final ViewTuple<TestFxmlViewResourceBundleWithoutController, TestViewModelWithResourceBundle> viewTuple =
FluentViewLoader
.fxmlView(TestFxmlViewResourceBundleWithoutController.class)
.codeBehind(codeBehind)
.viewModel(viewModel)
.resourceBundle(resourceBundle)
.load();



assertThat(viewTuple.getCodeBehind()).isEqualTo(codeBehind);
assertThat(viewTuple.getViewModel()).isEqualTo(viewModel);

assertThat(viewModel.resourceBundle).hasSameContent(resourceBundle);
assertThat(codeBehind.resourceBundle).hasSameContent(resourceBundle);
}

public static class TestJavaView extends VBox implements JavaView<TestViewModelWithResourceBundle> {
@InjectResourceBundle
ResourceBundle resourceBundle;
}


@Test
public void success_java_injectionOfResourceBundles() {
final ViewTuple<TestJavaView, TestViewModelWithResourceBundle> viewTuple =
FluentViewLoader
.javaView(TestJavaView.class)
.resourceBundle(resourceBundle)
.load();

final TestViewModelWithResourceBundle viewModel = viewTuple.getViewModel();
final TestJavaView view = viewTuple.getCodeBehind();

assertThat(view.resourceBundle).isNotNull().hasSameContent(resourceBundle);

assertThat(viewModel.resourceBundle).isNotNull().hasSameContent(resourceBundle);
}

@Test
public void success_java_injectionWithExistingViewModel() {
TestViewModelWithResourceBundle viewModel = new TestViewModelWithResourceBundle();

final ViewTuple<TestJavaView, TestViewModelWithResourceBundle> viewTuple = FluentViewLoader
.javaView(TestJavaView.class)
.resourceBundle(resourceBundle)
.viewModel(viewModel)
.load();

assertThat(viewTuple.getViewModel()).isEqualTo(viewModel);
final TestJavaView view = viewTuple.getCodeBehind();


assertThat(view.resourceBundle).isNotNull().hasSameContent(resourceBundle);
assertThat(viewModel.resourceBundle).isNotNull().hasSameContent(resourceBundle);
}


/**
* Both the View and ViewModel have {@link InjectResourceBundle} annotations (without optional argument)
* but no resourceBundle was provided at loading time. Therefore an exception is thrown.
*/
@Test
// @Ignore("until fixed. See issue #435")
public void fail_noResourceBundleGivenForViewAndViewModel() {
MvvmFX.setGlobalResourceBundle(null);

try {
FluentViewLoader.fxmlView(TestFxmlViewResourceBundle.class).load();

failBecauseExceptionWasNotThrown(RuntimeException.class);
} catch (Exception ex) {
assertThat(ExceptionUtils.getRootCause(ex)).isInstanceOf(IllegalStateException.class).hasMessageContaining(
"expects a ResourceBundle to be injected but no ResourceBundle was defined while loading.");
}
}

/**
* Only the ViewModel is using the {@link InjectResourceBundle} annotation
* but no resourceBundle was provided at loading time. Therefore an exception is thrown.
*/
@Test
public void fail_noResourceBundleGivenForViewModel() {
MvvmFX.setGlobalResourceBundle(null);

try {
FluentViewLoader.fxmlView(TestFxmlViewOnlyViewModelResourceBundle.class).load();

failBecauseExceptionWasNotThrown(RuntimeException.class);
} catch (Exception ex) {
assertThat(ExceptionUtils.getRootCause(ex)).isInstanceOf(IllegalStateException.class).hasMessageContaining(
"expects a ResourceBundle to be injected but no ResourceBundle was defined while loading.");
}
}

/**
* Only the View is using the {@link InjectResourceBundle} annotation
* but no resourceBundle was provided at loading time. Therefore an exception is thrown.
*/
@Test
public void fail_noResourceBundleGivenForView() {
MvvmFX.setGlobalResourceBundle(null);

try {
FluentViewLoader.fxmlView(TestFxmlViewOnlyViewResourceBundle.class).load();

failBecauseExceptionWasNotThrown(RuntimeException.class);
} catch (Exception ex) {
assertThat(ExceptionUtils.getRootCause(ex)).isInstanceOf(IllegalStateException.class).hasMessageContaining(
"expects a ResourceBundle to be injected but no ResourceBundle was defined while loading.");
}
}

}
Loading

0 comments on commit f65e5e8

Please sign in to comment.