-parameters flag for Java

-parameters flag for Java

de Anton Dil -
Número de respuestas: 5
I may be being a little lazy here in not having tried this out, but is it possible to read students' .class files and use reflection on them? I'm interested in finding out more about what they wrote.  In particular, can we get the .class files to contain parameter name information, as in Java 8 using the -parameters flag with the javac compiler? (And then read those .class files)

Thanks!
Anton


En respuesta a Anton Dil

Re: -parameters flag for Java

de Richard Lobb -

I'm not quite sure what you're trying to achieve, and I'm not really a Java guru, so I think you might have to experiment a bit. Just a couple of comments:

  • If you simply want to analyse what students submitted for your own interest rather than for marking purposes, I'd suggest just downloading all the responses to a quiz as an Excel spreadsheet, via the Moodle Quiz > Results > Responses menu. If you open that spreadsheet in Open Office or Excel and save that as a .csv file you can analyse it at your leisure. I use the Python csv module to pull out the actual answers. I recommend going via Excel rather than exporting all the responses from Moodle as a .csv file, which seems to have issues when the responses are code.
  • If you want to analyse student responses as part of the marking process then your template code will have to be a script that compiles the student code first and then inspects it before running it. I always write such scripts in Python, using the subprocess module for compiling and running the student code in (say) Java. But you can presumably do the scripting in Java. With such a script approach you should be able to pass whatever command-line options you like to the compile and execute phases.
Richard
En respuesta a Richard Lobb

Re: -parameters flag for Java

de Anton Dil -

Thanks for the reply Richard - it's the latter. Yes, I need to experiment. I thought there might be some restrictions in place on these kinds of activities, e.g. reflection is generally turned off in production systems.

En respuesta a Richard Lobb

Re: -parameters flag for Java

de Anton Dil -

Hi Richard,

I've now gone quite a long way with this, but I'm finding myself in a bit of a catch-22.

If Student_answer is not part of the Tester class in the usual way (instead I assign it to a string) I can compile and catch compilation errors myself. But then I can't run unit tests, as the student's code isn't visible in the Tester class. I can create .class files so I could load the student's classes dynamically, but this complicates the unit tests considerably. The student's .class files are created too late for Tester to include code that references the student's answer directly.

If the student's code is included in the class in the standard way then all works in the usual way - if their code contains errors then Tester won't compile, and I can't run my compilation code to catch those errors if Tester doesn't compile.

My idea was to use Precheck to do a free (no marks lost) check, including compilation error check, then Check to run the usual unit tests (with penalties for errors). Is there something in Twig that would allow me to selectively include student_answer perhaps? Or perhaps you can see another way around this problem...

Thanks!

Anton

En respuesta a Anton Dil

Re: -parameters flag for Java

de Richard Lobb -

Hi Anton

Since my Java's a bit rusty, I'm not sure I fully understand the problem. But the way I deal with issues like this in Python, say when scripting C questions, is firstly to get all the input data - student program, test code, etc - as strings. I like to do that first, to avoid cluttering the rest of the template with ugly Twig syntax. Then I write the student program to a file and try compiling it. If there are any errors, they get displayed and the process is aborted. Otherwise, and if it's not a precheck, I dynamically construct the tester (as a string) from the student program plus all the tests, write the string to a file, and compile and run that.

I'm not sure if it helps, but here's my Python get_test_cases function from one of my standard templates, whereTestCase is a class that wraps the test info. This function gets all the test data into an array of TestCase objects for use within a template grader - for simpler applications all you need is just the array of testcodes, probably.

def get_test_cases():
    """Return an array of Test objects from the template parameter TESTCASES"""
    test_cases = []
{% for TEST in TESTCASES %}
    testcode = """{{ TEST.testcode | e('py') }}\n"""
    stdin = """{{ TEST.stdin | e('py') }}\n"""
    extra = """{{ TEST.extra | e('py') }}\n"""
    expected = """{{ TEST.expected | e('py') }}\n"""
    display = """{{ TEST.display | e('py') }}\n"""
    hiderestiffail = """{{ TEST.hiderestiffail | e('py') }}\n"""
    mark = {{ TEST.mark }}
    useasexamplestring = """{{ TEST.useasexample | e('py')}}"""
    useasexample = useasexamplestring not in ['', '0']  # Tricky! Empty during validation.
    testtype = {{ TEST.testtype }}
    test_cases.append(TestCase(testcode, stdin, extra, expected, display, hiderestiffail, mark, useasexample, testtype))
{% endfor %}
    return test_cases

However, you may think that's too complicated. You ask "Is there something in Twig that would allow me to selectively include student_answer perhaps?". Certainly you could use a Twig if statement that tests the IS_PRECHECK template parameter to conditionally include the test data with the student program. Something like

{% if not IS_PRECHECK %}
{% for TEST in TESTCASES %}
    {
    {{ TEST.testcode }};
    {% if not loop.last %}
    System.out.println(SEPARATOR);
    {% endif %}
    }
{% endfor %}
{% endif %}

I'm not sure if that answers your question or not. Feel free to try again if I've missed the point.

Richard

En respuesta a Richard Lobb

Re: -parameters flag for Java

de Anton Dil -

Thank you again Richard...

This seems to be what I was looking for:

{% if not IS_PRECHECK %}
        {# include the student's code #}
       {{ STUDENT_ANSWER | replace({'public class ': 'class '}) }}
{% endif %}

Happy days - on to the next problem :-)

Regards,
Anton