Mod4j: Modeling for Java using Domain Specific Languages

When using derived attributes, executing the generated code results in a UnsupportedOperationException

Details

  • Type: Bug Bug
  • Status: Resolved Resolved
  • Priority: Critical Critical
  • Resolution: Fixed
  • Affects Version/s: 1.0.0, 1.0.1
  • Fix Version/s: 1.1.0
  • Labels:
    None
  • Number of attachments :
    0

Description

When marking a attribute as derived, the extension point for the corresponding domain class is filled with a setter method for that attribute. Initially the method is implemented to throw a UnsupportedOperationException. But this setter for this attribute is also always used in the dto translator of the dto where the business class is used. So out-of-the-box this will always lead to this Exception.

java.lang.UnsupportedOperationException: Not implemented
at org.company.recordshop.domain.Order.setTotalAmount(Order.java:48)
at org.company.recordshop.service.dto.translators.OrderDtoTranslator.fromDto(OrderDtoTranslator.java:88)
at org.company.recordshop.service.OrderServiceModelLocalServiceImplBase.createOrder(OrderServiceModelLocalServiceImplBase.java:182)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:301)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:77)
at org.mod4j.runtime.aspects.LoggingAspect.log(LoggingAspect.java:21)
at sun.reflect.GeneratedMethodAccessor100.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:627)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:616)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:64)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:77)
at org.mod4j.runtime.aspects.TimingAspect.time(TimingAspect.java:18)
at sun.reflect.GeneratedMethodAccessor99.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:627)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:616)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:64)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy18.createOrder(Unknown Source)
at org.company.recordshop.service.AssociationsServiceTest.setup(AssociationsServiceTest.java:66)
at org.company.recordshop.service.AssociationsServiceTest.testListAll(AssociationsServiceTest.java:96)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.springframework.test.context.junit4.SpringTestMethod.invoke(SpringTestMethod.java:198)
at org.springframework.test.context.junit4.SpringMethodRoadie.runTestMethod(SpringMethodRoadie.java:274)
at org.springframework.test.context.junit4.SpringMethodRoadie$2.run(SpringMethodRoadie.java:207)
at org.springframework.test.context.junit4.SpringMethodRoadie.runBeforesThenTestThenAfters(SpringMethodRoadie.java:254)
at org.springframework.test.context.junit4.SpringMethodRoadie.runWithRepetitions(SpringMethodRoadie.java:234)
at org.springframework.test.context.junit4.SpringMethodRoadie.runTest(SpringMethodRoadie.java:204)
at org.springframework.test.context.junit4.SpringMethodRoadie.run(SpringMethodRoadie.java:146)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:151)
at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

Activity

Hide
Eric Jan Malotaux added a comment -

Fixed by removing the generated getters and setters in the extension points; the developer has to implement them anyway for derived properties to work, so it is no use to generate non-functional code. The methods in the generated classes are still abstract, so the compiler will bring the methods to be implemented to the developer's attention.

The dto translators will not call setters for derived but not writable properties.

In the meta-model for the business domain DSL all properties are now by default not writable. This "writable" property is only applicable to derived properties. "Derived" now means implicitly "readonly", unless made explicitly writable by using the "writable" keyword.

Show
Eric Jan Malotaux added a comment - Fixed by removing the generated getters and setters in the extension points; the developer has to implement them anyway for derived properties to work, so it is no use to generate non-functional code. The methods in the generated classes are still abstract, so the compiler will bring the methods to be implemented to the developer's attention. The dto translators will not call setters for derived but not writable properties. In the meta-model for the business domain DSL all properties are now by default not writable. This "writable" property is only applicable to derived properties. "Derived" now means implicitly "readonly", unless made explicitly writable by using the "writable" keyword.
Hide
Johan Vogelzang added a comment - - edited

Eric Jan,

To avoid compilation problems after the generator has run, the abstract methods should also be generated into the extension that should implement these methods. A TODO should be added to bring it to the attention of developers. This is similar to the way we handle the validate method in business rule classes.
Example for the getter of derived attributes:

@Override
public float getLineAmount() {
    // TODO Mod4j-generated method stub. Implement this method manually.
    return 0;
}
Show
Johan Vogelzang added a comment - - edited Eric Jan, To avoid compilation problems after the generator has run, the abstract methods should also be generated into the extension that should implement these methods. A TODO should be added to bring it to the attention of developers. This is similar to the way we handle the validate method in business rule classes. Example for the getter of derived attributes:
@Override
public float getLineAmount() {
    // TODO Mod4j-generated method stub. Implement this method manually.
    return 0;
}
Hide
Jos Warmer added a comment -

Fixed by generating empty methods in the extension point class with TODO MOD4J comments.
Everything compiles ok now.

Show
Jos Warmer added a comment - Fixed by generating empty methods in the extension point class with TODO MOD4J comments. Everything compiles ok now.

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated:
    Resolved: