I have a class which handles errors, including exceptions. If an exception is caught, I will pass the exception as an argument to my exception/error handler.
try {
someTrowingFnc();
} catch (\Exception $e) {
this->error->exception($e);
}
Now I want to unit test this error handler and mock the exception.
I am finding it hard to mock the exception so that I can control the exception message, file and line.
$exceptionMock = $this->getMock('Exception', array(
'getFile',
'getLine',
'getMessage',
'getTrace'
)); // Tried all mock arguments like disable callOriginalConstructor
$exceptionMock->expects($this->any())
->method('getFile')
->willReturn('/file/name');
$exceptionMock->expects($this->any())
->method('getLine')
->willReturn('3069');
$exceptionMock->expects($this->any())
->method('getMessage')
->willReturn('Error test');
The results of the code below always returns NULL
$file = $exception->getFile();
$line = $exception->getLine();
$msg = $exception->getMessage();
Is there a work-around to mock exceptions or am I just doing something wrong?
The Exception class methods that return the error details such as getFile() etc are defined/declared as final methods. And this is one limitation of PHPUnit currently in mocking methods that are protected, private, and final.
Limitations
Please note that final, private and static methods cannot be stubbed or mocked. They are ignored by PHPUnit's test double functionality and retain their original behavior.
As seen here: https://phpunit.de/manual/current/en/test-doubles.html
It's a bit of a hack, but try adding something like this to your TestCase:
/**
* #param object $object The object to update
* #param string $attributeName The attribute to change
* #param mixed $value The value to change it to
*/
protected function setObjectAttribute($object, $attributeName, $value)
{
$reflection = new \ReflectionObject($object);
$property = $reflection->getProperty($attributeName);
$property->setAccessible(true);
$property->setValue($object, $value);
}
Now you can change the values.
$exception = $this->getMock('Exception');
$this->setObjectAttribute($exception, 'file', '/file/name');
$this->setObjectAttribute($exception, 'line', 3069);
$this->setObjectAttribute($exception, 'message', 'Error test');
Of course, you haven't really mocked the class, though this can still be useful if you have a more complex custom Exception. Also you won't be able to count how many times the method is called, but since you were using $this->any(), I assume that doesn't matter.
It's also useful when you're testing how an Exception is handled, for example to see if another method (such as a logger) was called with the the exception message as a parameter
The throwException() in PHPUnit TestCase class can take any instance of Throwable as param.
Here is an example that should pass if you have try/catch in FileWriterToBeTested and will fail if you do not have try/catch:
$this->reader = $this->getMockBuilder(Reader::class)->getMock();
$this->reader->method('getFile')->will(static::throwException(new \Exception()));
$file = new FileWriterToBeTested($this->reader);
static::assertNull($file->getFile('someParamLikePath'));
tested class sample:
class FileWriterToBeTested
{
/**
* #var Reader
*/
private $reader;
public function __construct(Reader $reader): void
{
$this->reader = $reader;
}
/**
* #return Reader
*/
public function getFile(string $path): void
{
try {
$this->reader->getFile($path);
} catch (\Exception $e) {
$this->error->exception($e);
}
}
}
Related
I want to control the same user access on some methods in my controller.
Currently, I use this :
$this->denyAccessUnlessGranted('ACCESS', $this->Player($toolRepository));
However I am forced to use this line and inject the ToolRepository into each method ...
What would be the easiest way to do it?
I saw that there was the IsGranted annotation but my subject needs to be a doctrine object to control access with my Vote.
/**
* #Route("/player")
*/
class PlayerController extends AbstractController
{
/**
* #Route("/", name="player")
* #throws Exception
*/
public function Player(ToolRepository $toolRepository): \App\Entity\Tool
{
$playerTool = 'TestTool2';
$tool = $toolRepository->findOneBy(array('libelle' => $playerTool));
if (!$tool) {
throw new Exception('Tool : ' . $playerTool . 'not found!');
}
return $tool;
}
/**
* #Route("/main", name="player")
* #IsGranted ("ACCESS", subject="tool")
* #throws Exception
*/
public function mainPlayer(PlayerRepository $playerRepository, ToolRepository $toolRepository): Response
{
$this->denyAccessUnlessGranted('ACCESS', $this->Player($toolRepository));
$players = $playerRepository->findAll();
return $this->render('player/player_mainpage.html.twig', ['players'=>$players]);
}
}
I think this ressource should answer you: Symfony voters.
You'll put your security logic in your custom voter which will be called in every function of your controller (or every methods where you want to control access) isGranted() function.
Calling your Player() function is a easier way to do this for beginner, you can keep like that but you shouldn't put it in Controller and use a Service instead .
Edit:
You may store your ToolRepository as Controller private property and inject it in a __construct() method so you don't have to inject ToolRepository in each method
//Original method:
#Autowired
private ConversionServiceValidator validator;
public CRSConversionResult convertCRS(ConvertCrsVo convertCrsVo) throws Exception {
if (validator.isSameSourceAndTarget(convertCrsVo))
throw new ValidationException(Constants.BADREQUEST);
if (convertCrsVo.getPreferredTransforms() != null) {
List<TransformVo> preferredTransformList = new ArrayList<>();
for (TransformVo transformVo : convertCrsVo.getPreferredTransforms()) {
preferredTransformList.add(getPerfByCode(transformVo));
}
convertCrsVo.setPreferredTransforms(preferredTransformList);
}
convertCrsVo.setSourceCRS(getCrsVoByCode(convertCrsVo.getSourceCRS()));
convertCrsVo.setTargetCRS(getCrsVoByCode(convertCrsVo.getTargetCRS()));
convertCrsVo = validator.replaceCoordinates(convertCrsVo);
logger.info("ShellGeodeticService::convertCRS::Request to GeoCalService convertpoints::" + mapper.writeValueAsString(convertCrsVo));
ConvertPointsResponse response = geoCalService.convertCRS(convertCrsVo);
CRSConversionResult result = new CRSConversionResult();
result.setCriteriaMessage(response.getCriteriaMessage());
result.setResultPoints(response.getResultPoints());
result.setTransformName(response.getTransformName());
result.setTransformDescription(response.getTransformDescription());
// added schema as per pbi 195298
List<ConvertedTransformsResult> transformsResults = new ArrayList<>();
if (response.getTransforms() != null || !response.getTransforms().isEmpty())
response.getTransforms().stream().forEach(
t -> transformsResults.add(new ConvertedTransformsResult().getConvertedTransformsResult(t)));
result.setTransforms(transformsResults);
String logmessage=generateLogMessage(result,convertCrsVo);
logger.info(logmessage);
validator.isResponseValid(result);
return result;
}
//The testcase for the above method
#Test
public void testconvertCRSJob() throws Exception{
ConvertCrsVo convertCrsVo = TestDataFactory.getConvertCrsVo();
CRSConversionResult crsConversionResult = TestDataFactory.getCRSConversionResult();
ConversionServiceValidator conversionServiceValidatorMock = mock(ConversionServiceValidator.class);
Mockito.when(geoCalService.convertCRS(Mockito.any()))
.thenReturn(TestDataFactory.getConvertPointsResponse(convertCrsVo));
Mockito.when(validator.replaceCoordinates(convertCrsVo))
.thenReturn(TestDataFactory.getConvertCrsVo());
Mockito.when(geoCalService.search(Mockito.any(SearchFilter.class)))
.thenReturn(TestDataFactory.getSearchResultResponseForCRS());
Mockito.when(shellGeodeticService.convertCRS(convertCrsVo))
.thenReturn(TestDataFactory.getCRSConversionResult());
shellGeodeticService.convertCRSJob();
}
The error that i am getting is as below:
org.mockito.exceptions.misusing.CannotStubVoidMethodWithReturnValue:
'isResponseValid' is a void method and it cannot be stubbed with a return value!
Voids are usually stubbed with Throwables:
doThrow(exception).when(mock).someVoidMethod();
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. The method you are trying to stub is overloaded. Make sure you are calling the right overloaded version.
2. Somewhere in your test you are stubbing final methods. Sorry, Mockito does not verify/stub final methods.
3. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
4. Mocking methods declared on non-public parent classes is not supported.
at com.shell.geodetic.GeodeticConvertionApiAppTests.testconvertCRSJob(GeodeticConvertionApiAppTests.java:1783)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
Can someone help me on how to stub the void method "isResponseValid" ? I tried around 100 combinations that i saw in SOF and nothing worked. Thanks for the help in advance.
*Edit
Class ConversionServiceValidator {
public void isResponseValid(CRSConversionResult response) throws InvalidDataException {
if (response.getResultPoints().isEmpty() || response.getResultPoints() == null) {
throw new ValidationException("Request body has incorrect format");
} else {
for (Point point : response.getResultPoints()) {
if (point.getX().trim().equals("0") || point.getY().trim().equals("0")) {
throw new InvalidDataException(400, "Bad Request", "WARNING: Not all points could be converted",
response);
}
}
}
It is a mock #InjectMocks ShellGeodeticService shellGeodeticService;
shellGeodeticService is not a mock. #InjectMocks is used for the class under test, where the mocks are injected into.
That implies you can not use
Mockito.when(shellGeodeticService.convertCRS(convertCrsVo))
.thenReturn(TestDataFactory.getCRSConversionResult());
in your test as only mocks(or spys) can be used within Mockito.when.
Actually im trying to run test case for shellGeodeticService.convertCRS() and since it calls isResponseValid method internally , i have to mock that also right?
No, that is incorrect. If validator is a mock every method invocation will do nothing by default. So, unless you want to throw an exception, you do not need to define anything.
As your question lacks some details, I assume a complete version of your test could be similiar to this:
#InjectMocks
ShellGeodeticService shellGeodeticService;
#Mock
ConversionServiceValidator validator;
#Mock
... geoCalService; // some unknown class
#Test
public void testconvertCRSJob() throws Exception{
ConvertCrsVo convertCrsVo = TestDataFactory.getConvertCrsVo();
// Note sure whether this is correct by your logic as there is no `replacement` happening.
Mockito.when(validator.replaceCoordinates(convertCrsVo)).thenReturn(convertCrsVo);
Mockito.when(geoCalService.convertCRS(Mockito.any())).thenReturn(TestDataFactory.getConvertPointsResponse(convertCrsVo));
CRSConversionResult result = shellGeodeticService.convertCRS();
// do some assertions on the result
}
As validator is a mock:
validator.isSameSourceAndTarget(convertCrsVo) returns false be default
validator.isResponseValid( ... ) does nothing by default
As you did not add the methods getCrsVoByCode, getPerfByCode and generateLogMessage take note that if there are any further interactions with the mocked objects you'll need to add them.
(eg.: a call to geoCalService.search is not visible in your test code, so I removed the behaviour definition from the test displayed above)
I think everyone can agree that JFileChooser is really poop. So I was looking for an alternative and found out that JavaFX has got a great FileChooser class. So now the obvious question: how can I embed that neat FileChooser into my Swing application?
Needless to say, I did some research before I posted this, and this is what I found so far: link to a Reddit post.
The code of that JavaFXFileDialog class is very interesting, but it does not close when I exit my application (JavaFX seems to continue running in the background). Also I am missing some fields I can pass to the FileChooser like the path to set default directory. And I don't like how it is static.
I am grateful for any input.
The code of that dialog has multiple problems besides the ones you mention. For example, it doesn't handle the situation when JavaFX platform shuts down right after isJavaFXStillUsable() is called, but before the call to Platform.runLater(), which will still make it hang forever. I don't like that huge synchronized block either, although there don't seem to be any real problems with that. I also don't get why "the stupid synchronization object had to be a field" - each invocation of chooseFileWithJavaFXDialog() is independent of each other, so it could just as well use a local final lock (even that array would do fine).
The right way to make JVM exit correctly is to call Platform.exit() when you are shutting down your application (perhaps in windowClosed() of your main window). You need to do this manually because the chooser class has no idea whether you need JavaFX any more or not, and there is no way to restart it once it has been shut down.
That code inspired me to develop a utility class for calling just about any code in the JavaFX event thread, and get the result back to the calling thread, handling various exceptions and JavaFX states nicely:
/**
* A utility class to execute a Callable synchronously
* on the JavaFX event thread.
*
* #param <T> the return type of the callable
*/
public class SynchronousJFXCaller<T> {
private final Callable<T> callable;
/**
* Constructs a new caller that will execute the provided callable.
*
* The callable is accessed from the JavaFX event thread, so it should either
* be immutable or at least its state shouldn't be changed randomly while
* the call() method is in progress.
*
* #param callable the action to execute on the JFX event thread
*/
public SynchronousJFXCaller(Callable<T> callable) {
this.callable = callable;
}
/**
* Executes the Callable.
* <p>
* A specialized task is run using Platform.runLater(). The calling thread
* then waits first for the task to start, then for it to return a result.
* Any exception thrown by the Callable will be rethrown in the calling
* thread.
* </p>
* #param startTimeout time to wait for Platform.runLater() to <em>start</em>
* the dialog-showing task
* #param startTimeoutUnit the time unit of the startTimeout argument
* #return whatever the Callable returns
* #throws IllegalStateException if Platform.runLater() fails to start
* the task within the given timeout
* #throws InterruptedException if the calling (this) thread is interrupted
* while waiting for the task to start or to get its result (note that the
* task will still run anyway and its result will be ignored)
*/
public T call(long startTimeout, TimeUnit startTimeoutUnit)
throws Exception {
final CountDownLatch taskStarted = new CountDownLatch(1);
// Can't use volatile boolean here because only finals can be accessed
// from closures like the lambda expression below.
final AtomicBoolean taskCancelled = new AtomicBoolean(false);
// a trick to emulate modality:
final JDialog modalBlocker = new JDialog();
modalBlocker.setModal(true);
modalBlocker.setUndecorated(true);
modalBlocker.setOpacity(0.0f);
modalBlocker.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
final CountDownLatch modalityLatch = new CountDownLatch(1);
final FutureTask<T> task = new FutureTask<T>(() -> {
synchronized (taskStarted) {
if (taskCancelled.get()) {
return null;
} else {
taskStarted.countDown();
}
}
try {
return callable.call();
} finally {
// Wait until the Swing thread is blocked in setVisible():
modalityLatch.await();
// and unblock it:
SwingUtilities.invokeLater(() ->
modalBlocker.setVisible(false));
}
});
Platform.runLater(task);
if (!taskStarted.await(startTimeout, startTimeoutUnit)) {
synchronized (taskStarted) {
// the last chance, it could have been started just now
if (!taskStarted.await(0, TimeUnit.MILLISECONDS)) {
// Can't use task.cancel() here because it would
// interrupt the JavaFX thread, which we don't own.
taskCancelled.set(true);
throw new IllegalStateException("JavaFX was shut down"
+ " or is unresponsive");
}
}
}
// a trick to notify the task AFTER we have been blocked
// in setVisible()
SwingUtilities.invokeLater(() -> {
// notify that we are ready to get the result:
modalityLatch.countDown();
});
modalBlocker.setVisible(true); // blocks
modalBlocker.dispose(); // release resources
try {
return task.get();
} catch (ExecutionException ex) {
Throwable ec = ex.getCause();
if (ec instanceof Exception) {
throw (Exception) ec;
} else if (ec instanceof Error) {
throw (Error) ec;
} else {
throw new AssertionError("Unexpected exception type", ec);
}
}
}
}
The only part that worries me is that modality trick. It could very well work
without it (just remove any code that references modalBlocker and modalityHatch), but then the Swing part of the application won't just stop responding to the user input (which is what we need), but also will freeze,
stopping updates, progress bars and so on, which is not so nice. What worries me about this particular trick is that the invisible dialog may be not so invisible in some L&Fs, or cause other unwanted glitches.
I deliberately didn't include any initialization or shutdown code because I believe it doesn't belong there. I would just do new JFXPanel() in main() and Platform.exit() wherever I perform other shutdown tasks.
Using this class, calling for a FileChooser is easy:
/**
* A utility class that summons JavaFX FileChooser from the Swing EDT.
* (Or anywhere else for that matter.) JavaFX should be initialized prior to
* using this class (e. g. by creating a JFXPanel instance). It is also
* recommended to call Platform.setImplicitExit(false) after initialization
* to ensure that JavaFX platform keeps running. Don't forget to call
* Platform.exit() when shutting down the application, to ensure that
* the JavaFX threads don't prevent JVM exit.
*/
public class SynchronousJFXFileChooser {
private final Supplier<FileChooser> fileChooserFactory;
/**
* Constructs a new file chooser that will use the provided factory.
*
* The factory is accessed from the JavaFX event thread, so it should either
* be immutable or at least its state shouldn't be changed randomly while
* one of the dialog-showing method calls is in progress.
*
* The factory should create and set up the chooser, for example,
* by setting extension filters. If there is no need to perform custom
* initialization of the chooser, FileChooser::new could be passed as
* a factory.
*
* Alternatively, the method parameter supplied to the showDialog()
* function can be used to provide custom initialization.
*
* #param fileChooserFactory the function used to construct new choosers
*/
public SynchronousJFXFileChooser(Supplier<FileChooser> fileChooserFactory) {
this.fileChooserFactory = fileChooserFactory;
}
/**
* Shows the FileChooser dialog by calling the provided method.
*
* Waits for one second for the dialog-showing task to start in the JavaFX
* event thread, then throws an IllegalStateException if it didn't start.
*
* #see #showDialog(java.util.function.Function, long, java.util.concurrent.TimeUnit)
* #param <T> the return type of the method, usually File or List<File>
* #param method a function calling one of the dialog-showing methods
* #return whatever the method returns
*/
public <T> T showDialog(Function<FileChooser, T> method) {
return showDialog(method, 1, TimeUnit.SECONDS);
}
/**
* Shows the FileChooser dialog by calling the provided method. The dialog
* is created by the factory supplied to the constructor, then it is shown
* by calling the provided method on it, then the result is returned.
* <p>
* Everything happens in the right threads thanks to
* {#link SynchronousJFXCaller}. The task performed in the JavaFX thread
* consists of two steps: construct a chooser using the provided factory
* and invoke the provided method on it. Any exception thrown during these
* steps will be rethrown in the calling thread, which shouldn't
* normally happen unless the factory throws an unchecked exception.
* </p>
* <p>
* If the calling thread is interrupted during either the wait for
* the task to start or for its result, then null is returned and
* the Thread interrupted status is set.
* </p>
* #param <T> return type (usually File or List<File>)
* #param method a function that calls the desired FileChooser method
* #param timeout time to wait for Platform.runLater() to <em>start</em>
* the dialog-showing task (once started, it is allowed to run as long
* as needed)
* #param unit the time unit of the timeout argument
* #return whatever the method returns
* #throws IllegalStateException if Platform.runLater() fails to start
* the dialog-showing task within the given timeout
*/
public <T> T showDialog(Function<FileChooser, T> method,
long timeout, TimeUnit unit) {
Callable<T> task = () -> {
FileChooser chooser = fileChooserFactory.get();
return method.apply(chooser);
};
SynchronousJFXCaller<T> caller = new SynchronousJFXCaller<>(task);
try {
return caller.call(timeout, unit);
} catch (RuntimeException | Error ex) {
throw ex;
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
return null;
} catch (Exception ex) {
throw new AssertionError("Got unexpected checked exception from"
+ " SynchronousJFXCaller.call()", ex);
}
}
/**
* Shows a FileChooser using FileChooser.showOpenDialog().
*
* #see #showDialog(java.util.function.Function, long, java.util.concurrent.TimeUnit)
* #return the return value of FileChooser.showOpenDialog()
*/
public File showOpenDialog() {
return showDialog(chooser -> chooser.showOpenDialog(null));
}
/**
* Shows a FileChooser using FileChooser.showSaveDialog().
*
* #see #showDialog(java.util.function.Function, long, java.util.concurrent.TimeUnit)
* #return the return value of FileChooser.showSaveDialog()
*/
public File showSaveDialog() {
return showDialog(chooser -> chooser.showSaveDialog(null));
}
/**
* Shows a FileChooser using FileChooser.showOpenMultipleDialog().
*
* #see #showDialog(java.util.function.Function, long, java.util.concurrent.TimeUnit)
* #return the return value of FileChooser.showOpenMultipleDialog()
*/
public List<File> showOpenMultipleDialog() {
return showDialog(chooser -> chooser.showOpenMultipleDialog(null));
}
public static void main(String[] args) {
javafx.embed.swing.JFXPanel dummy = new javafx.embed.swing.JFXPanel();
Platform.setImplicitExit(false);
try {
SynchronousJFXFileChooser chooser = new SynchronousJFXFileChooser(() -> {
FileChooser ch = new FileChooser();
ch.setTitle("Open any file you wish");
return ch;
});
File file = chooser.showOpenDialog();
System.out.println(file);
// this will throw an exception:
chooser.showDialog(ch -> ch.showOpenDialog(null), 1, TimeUnit.NANOSECONDS);
} finally {
Platform.exit();
}
}
}
Using this class, you may either initialize your chooser in the factory method, or, if you need to perform different initialization for each call, you could pass a custom method to showDialog() instead:
System.out.println(chooser.showDialog(ch -> {
ch.setInitialDirectory(new File(System.getProperty("user.home")));
return ch.showOpenDialog(null);
}));
I'm trying to implement a custom marshaller in Grails. Here's the marshaller:
class AdultPlanningMarshaller implements ObjectMarshaller<JSON> {
boolean supports(Object theObject)
{
return theObject instanceof AdultPlanning
}
void marshalObject(Object theObject, JSON theConverter)
{
AdultPlanning adult = (AdultPlanning)theObject
JSONWriter writer = theConverter.getWriter()
writer.object()
writer.key('id').value(adult.id)
...
writer.endObject()
}
}
I'm registering it in bootstrap.groovy and when I run my integration tests, the supports method fires correctly and the marshalObject method is called with the right object and a JSON object.
When I hit the:
writer.object()
call, an exception gets thrown:
org.codehaus.groovy.grails.web.json.JSONException: Misplaced object: expected mode of INIT, OBJECT or ARRAY but was DONE
So it looks like the writer has already done something to completion, but I have no clue what.
There's not a lot of documentation on JSON marshallers and examples are thin on the ground, but I think I've done this right but it sure isn't working. Any hints would be appreciated.
Further work with the debugger seems to indicate that the object marshaller is being called twice, although breakpoints only happen on the 2nd call for some reason. The first time through it seems to work just fine since the JSONWriter that I get via theConverter.getWriter() when the breakpoint DOES work has the JSON of the object correctly marshalled. It's the 2nd call that is blowing up since the object has ALREADY been marshalled and the JSONWriter is no longer in the "init" state. There's nothing obviously available to tell the difference between the two calls, but why it the marshaller being called twice?
As requested, here's the controller. It's the show action that's being triggered:
class PrimaryController extends RestfulController implements AlwaysRenderJsonException {
def springSecurityService
def familyService
static responseFormats = ['json']
PrimaryController() {
/*
* Tell the base class the name of the resource under management.
*/
super(Primary)
}
#Override
protected Primary createResource() {
//def instance = super.createResource()
//TODO: Should be able to run the above line but there is an issue GRAILS-10411 that prevents it.
// Code from parent is below, as soon as the jira is fixed, remove the following lines:
Primary instance = resource.newInstance()
bindData instance, this.getObjectToBind()
//Code from super ends here
def family = familyService.safeGetFamily(params.long('familyId'))
familyService.addAdultToFamily(instance, family) // Add the primary member to the family.
return instance
}
/**
* Deletes a resource for the given id
* #param id The id
*/
#Override
def delete() {
if(handleReadOnly()) {
return
}
Child instance = queryForResource(params.id)
if (instance == null) {
notFound()
return
}
/*
* Because of the multiple belongsTo relationships of events, you have to get rid of all
* the events and make the profiles consistent BEFORE deleting the person instance.
*/
instance.removePerson()
request.withFormat {
'*'{ render status: NO_CONTENT } // NO CONTENT STATUS CODE
}
}
#Override
protected List<Primary> listAllResources(Map params) {
if (params.familyId == null)
{
throw new ESPException("params.familyId may not be null")
}
def user = springSecurityService.loadCurrentUser()
return \
AdultPlanning.where {
family.id == params.familyId \
&& family.user == user \
&& typeOfPerson == PeopleTypeEnum.PRIMARY
}.list()
}
#Override
protected Primary queryForResource(Serializable id) {
def inst = familyService.safeGetAdult(Long.parseLong(id), params.long('familyId'))
/*
* It was safe to access the requested id, but the requested id may NOT be a primary
* so we need to check.
*/
return (inst instanceof Primary ? inst : null)
}
/**
* Show the primary for the specified family.
*
* #return
*/
#Override
def show() {
Primary primary = familyService.safeGetFamily(params.long('familyId'))?.primary
respond primary
}
}
And the Integration test that triggers it:
void "We should be able to show a primary."() {
given:
family.addToAdults(new Primary(firstName: "Barney"))
family.save()
family.adults.each { it.save() }
when:
controller.response.reset()
resetParameters(controller.params, [familyId: family.id])
controller.request.method = 'GET'
controller.show()
then:
1 * mSpringSecurityService.loadCurrentUser() >> user
controller.response.json
controller.response.json.firstName == "Barney"
}
Well, this is embarrassing.
I use IntelliJ as my Java/Groovy IDE. I had a work related thing to do this morning and quit IntelliJ. When I restarted IntelliJ, the problem described above that had been completely reproducible was no longer happening and the appropriate JSON was being produced under all circumstances.
So it appears that the IntelliJ state somehow got corrupted and the restart cleared it out.
Problem solved.
I guess.
Thanks for the help/suggestions.
As OP mentioned, this error can be triggered because of IntelliJ :
org.codehaus.groovy.grails.web.json.JSONException: Misplaced object: expected mode of INIT, OBJECT or ARRAY but was DONE
Indeed, when debugging the marshaller (for example), IntelliJ displays the "toString()" of the variable, which causes the change of the mode from INIT to DONE.
You may want to remove your breakpoints when facing this issue ;)
The only reason for this can be that where you have started writer.object() for some nested object or array response but missed to write writer.endObject() or you have wrote it two times.
So double check your custom marshaller for all write object.
Reference: https://github.com/grails/grails-core/blob/65b42b66821b32d4efb3a229da99691a00575d60/grails-web-common/src/main/groovy/org/grails/web/json/JSONWriter.java#L258
Hope This helps!
Thanks,
SA
I have a little problem, I'm trying to send a json response, but all I get is a empty object all the time.
So here is my code:
//Get the data from DB
$template = $this->getDoctrine()
->getRepository('EVRYgroBundle:Template')
->findOneBy(
array('active' => 1)
);
if (!$template) {
throw $this->createNotFoundException(
'No product found for id '
);
}
//Send the response
$response = new Response();
$response->setContent(json_encode($template));
return $response;
And when I'm viewing it all it shows is {}
And I have also tried with the jsonResponse and with this code:
$response = new JsonResponse();
$response->setData($template);
And I have no idea what i'm doing wrong!
json_encode expects an array as first parameter to be given in. When you call it with an object the public properties will may be displayed. To keep the properties protected (as they should be) you can add a expose function to your entity:
/**
* delivers all properties and values of the entity easily
*
* #return array
*/
public function expose()
{
return get_object_vars($this);
}
and then call
$response->setData(json_encode($template->expose()));
This way you keep your entity clean with only access via getter and setter methods and you can access all properties via json still.
Well I found the problem, the problem was that some variables that holds the information from the db was set to protected and not public.