Announcement Announcement Module
Collapse
No announcement yet.
Problem creating ManyToMany relationship using abstract types Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problem creating ManyToMany relationship using abstract types

    Hi,

    I have created a roo project with a collection of classes that can be described by the following class diagram

    Attachment

    I recognize that this class structure is trivially simple, but I have pared down this example from a more complicated project that was suffering from the same problem. The digram is showing a class "ContactConfiguration" with a ManyToMany relationship to the abstract "Channel" class through the field "channels". The class "PhoneChannel" extends "Channel" and introduces the field "name".

    I created this project through STS using the "File->New->Spring Roo Project" menu item. I then added a persistence provider, entities, fields and web scaffolding using the following set of roo commands:

    Code:
    // Spring Roo 1.2.1.RELEASE [rev 6eae723] log opened at 2012-04-09 11:07:22
    project --topLevelPackage com.sample --projectName roo-conversion-project --java 6 --packaging JAR
    // Spring Roo 1.2.1.RELEASE [rev 6eae723] log closed at 2012-04-09 11:07:22
    // Spring Roo 1.2.1.RELEASE [rev 6eae723] log opened at 2012-04-09 11:07:27
    jpa setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY
    entity jpa --class com.sample.domain.ContactConfiguration
    field string --fieldName name --notNull
    entity jpa --class ~.domain.Channel --abstract --inheritanceType SINGLE_TABLE
    entity jpa --class ~.domain.PhoneChannel --extends ~.domain.Channel --testAutomatically
    field string --fieldName name --notNull
    focus --class ~.domain.ContactConfiguration
    field set --fieldName channels --type ~.domain.Channel
    web mvc setup
    web mvc all --package ~.web
    When I deploy my web project to my local Tomcat 6 server and attempt to create a single "ContactConfiguration" that references a single "PhoneChannel", the application displays the message "Sorry, we encountered an internal error" and I see this strack trace in the Tomcat console:

    Code:
    Apr 9, 2012 11:12:10 AM org.apache.catalina.core.ApplicationDispatcher invoke
    SEVERE: Servlet.service() for servlet jsp threw exception
    org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type @javax.persistence.ManyToMany org.hibernate.collection.PersistentSet<@javax.persistence.ManyToMany com.sample.domain.Channel> to type java.lang.String
    	at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:475)
    	at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175)
    	at org.springframework.expression.spel.support.StandardTypeConverter.convertValue(StandardTypeConverter.java:66)
    	at org.springframework.expression.common.ExpressionUtils.convertTypedValue(ExpressionUtils.java:67)
    	at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:98)
    <truncated for brevity>...
    I attempted to isolate the problem by creating a separate Roo project that does not use an abstract class and instead has a "ContactConfiguration" referencing a concrete "Channel" class directly. This class structure does not exhibit the problem and appears to work as expected. I am now certain that the root cause of this problem has something to do with Roo attempting to build scaffolding for entities that are extensions of abstract classes. This problem is 100% reproduce-able in my environment (see below for tools and versions) using the roo commands referenced above.

    Two questions:

    1. Is this a bug in Roo? It seems like Roo should be able to handle this. If this is a bug, I'd be happy to open an issue in JIRA
    2. How can I go about working around this issue in the meantime? It seems like I need to add a Converter to my ApplicationConversionServiceFactory but I am not exactly sure what I should be adding (I'm a bit of a Spring newb and could use some detailed advice)

    Here is a little info on my environment:
    Mac OSX 10.7.3 (Lion), Apache Tomcat v6.0.35, STS 2.9.1.Release, Roo 1.2.1.Release, Java(TM) SE Runtime Environment (build 1.6.0_29-b11-402-11D50d)

    Thanks
    Attached Files

  • #2
    Did you ever find a solution to this? I have a ManyToMany relation that's getting the same error, although the class in question is not abstract at all.

    In my main entity, I have the relation defined as:
    Code:
    @ManyToMany(cascade = CascadeType.ALL)
        private Set<ArtCategoryPrice> prices = new HashSet<ArtCategoryPrice>();
    The ArtCategoryPrice entity is super-simple:
    Code:
    package com.gradient.art.domain;
    
    import org.springframework.roo.addon.javabean.RooJavaBean;
    import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
    import org.springframework.roo.addon.json.RooJson;
    import org.springframework.roo.addon.tostring.RooToString;
    
    @RooJavaBean
    @RooToString
    @RooJson
    @RooJpaActiveRecord
    public class ArtCategoryPrice {
    
        private float amount;
    }
    Single field, no reverse relationship at all. I thought of adding a custom converter, but the generated ApplicationConversionServiceFactoryBean class now shows the installFormatters() method as deprecated, and I haven't found anything that instructs how to replace it.

    I am curious to see how you managed to get around the problem. Perhaps I might just start a dummy project and see what gets generated, or just add the custom converter the old way and worry about the deprecation at a later time.

    Update:
    I added a custom converter as mentioned above as such:
    Code:
    	public Converter<Set<ArtCategoryPrice>, String> getSetOfArtCategoryPriceToStringConverter() {
    		return new Converter<Set<ArtCategoryPrice>, String>() {
    			@Override
    			public String convert(Set<ArtCategoryPrice> source) {
    				StringBuilder strBldr = new StringBuilder();
    				for(ArtCategoryPrice price :  source) {
    					if(strBldr.length()>0)
    						strBldr.append(",");
    					strBldr.append(price.getAmount());
    				}
    				return strBldr.toString();
    			}
    		};
    	}
    However, now I am getting this strange exception:
    Code:
    Caused by: java.lang.ClassCastException: com.gradient.art.domain.ArtCategory cannot be cast to com.gradient.art.domain.ArtCategoryPrice
    	at com.gradient.art.web.ApplicationConversionServiceFactoryBean$1.convert(ApplicationConversionServiceFactoryBean.java:30)
    	at com.gradient.art.web.ApplicationConversionServiceFactoryBean$1.convert(ApplicationConversionServiceFactoryBean.java:1)
    	at org.springframework.core.convert.support.GenericConversionService$ConverterAdapter.convert(GenericConversionService.java:517)
    	at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:35)
    	... 153 more
    Why would it even try to convert a Set<ArtCategory> using a converter for Set<ArtCategoryPrice>? It appears Spring is trying to "best-fit" a conversion from another member of my ArtCategory entity:
    Code:
    @ManyToMany(cascade = CascadeType.ALL, fetch=FetchType.LAZY)
        private Set<com.gradient.art.domain.ArtCategory> childCategories = new HashSet<com.gradient.art.domain.ArtCategory>();
    So, I guess I will continue down the rabbit hole, making converters for each item that Spring is complaining about.

    Update 2:
    Even after adding the following:
    Code:
    	public Converter<Set<ArtCategory>, String> getSetOfArtCategoryToStringConverter() {
    		return new Converter<Set<ArtCategory>, String>() {
    			@Override
    			public String convert(Set<ArtCategory> source) {
    				StringBuilder strBldr = new StringBuilder();
    				for(ArtCategory category :  source) {
    					if(strBldr.length()>0)
    						strBldr.append(",");
    					strBldr.append(category.getName());
    				}
    				return strBldr.toString();
    			}
    		};
    I am getting the exact same error as mentioned in the first update. Not sure why Spring would be trying to use a converter typed to handle Set<ArtCategoryPrice> for a Set<ArtCategory>. This is forcing me to write some very ugly code in the first converter.
    Last edited by mbabauer; Apr 28th, 2012, 08:16 AM.

    Comment


    • #3
      Sorry for the delay in getting back to this...

      Yes, I was able to eventually resolve this issue and I did so by adding the following method to my ApplicationConversionServiceFactoryBean:

      Code:
      public Converter<Channel, String> getChannelToStringConverter() {
              return new org.springframework.core.convert.converter.Converter<com.sample.domain.Channel, java.lang.String>() {
                  public String convert(Channel channel) {
                      return new StringBuilder().append(channel.getName()).toString();
                  }
              };
          }
      I guess the logic I was following was to heed the complaint in the initial exception. If Spring couldn't find a converter for Channels to Strings, I created a method that returned one.

      Comment


      • #4
        I'm having the same problem.
        Roo has already generated converters for all my domain types in the ApplicationConversionServiceFactoryBean_Roo_Conver sionService class, so if I add converters get<MyType>ToStringConverter methods in ApplicationConversionServiceFactoryBean, I get conflicts. no joy.

        Comment


        • #5
          I was able to resolve this by rerunning

          web mvc all --package ~.web

          Comment

          Working...
          X