Skip navigation

I was upgrading my application from Spring 2.5.6 + Spring Security 2.0.x to the latest 3.0 RC releases. After modifying my Maven pom.xml files to accomodate for the new artifact naming conventions, I still couldn’t get my application context to load due to a SAX exception:

org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 37 in XML document from class path resource [security-config.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'security:authentication-provider'.

I found myself spending almost an hour trying to figure out what’s wrong with my configuration file. Was I missing a JAR file? no, everything seems to be in its right place (you WILL want to make sure that you’re including spring-security-config.jar, though!), Eclipse didn’t detect anything wrong with the config file. In my despair, I turned to Security Namespace Configuration chapter of the Spring Security 3 reference manual. There I noticed the following paragraph:

  <authentication-manager>
    <authentication-provider>
      <user-service>
        <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
        <user name="bob" password="bobspassword" authorities="ROLE_USER" />
      </user-service>
    </authentication-provider>
  </authentication-manager>

Turning to my own configuration file, I saw this:

<security:authentication-provider user-service-ref="userService">
   <security:password-encoder ref="passwordEncoder">
      <security:salt-source user-property="username"/>
   </security:password-encoder>
</security:authentication-provider>

<security:authentication-manager alias="authenticationManager"/>

Apparently, while in Spring Security 2.x the authentication-provider tag used to be a root-level citizen, now it must live inside the authentication-manager definition.

I hope this will save some other folks some time when migrating to the 3.x Spring stack.

Even though I’ve been working with Hibernate for 3 years now, I’ve only just run into this issue – most likely because in past projects we’ve used POJO generations and now, for the first time in a real life project, I’m using the Schema Export tool.

It turns out that, for some odd reason, when creating foreign keys for OneToMany / ManyToOne relationships, Hibernate completely ignore the @Cascade annotations or the cascade keyword of the join annotation.

For instance, consider the following model:


@Entity
public class Cat {

 @Id
 @GeneratedValue
 @Column
 private Long id;

 @Column
 private String name;

 @OneToMany(mappedBy = "parent", cascade = {CascadeType.ALL})
 @ForeignKey(name = "FK_KITTEN_PARENT")
 private List kittens = new ArrayList();

}

@Entity
public class Kitten {

 @Id
 @Column
 @GeneratedValue
 private Long id;

 @ManyToOne(cascade = CascadeType.ALL)
 private Cat parent;

 @Column
 private String name;
}

The resulting DDL for these two classes will be:

create table Cat (id bigint not null auto_increment, name varchar(255), primary key (id)) ENGINE=InnoDB

create table Kitten (id bigint not null auto_increment, name varchar(255), parent_id bigint, primary key (id)) ENGINE=InnoDB

alter table Kitten add index FK_KITTEN_PARENT (parent_id), add constraint FK_KITTEN_PARENT foreign key (parent_id) references Cat (id)

This behavior does not seem to be documented anywhere. The Hibernate guys seem to think it’s natural for people to assume that the CascadeType and @Cascade definitions are not translated into DDL. What Hibernate does, instead of generating DDL, is automatically deleting the children (Kittens, in our case) of a deleted parent, when you use the Criteria API. And what if you happen to use HQL? tough.

Fortunately, there IS a solution. It involves using the not-so-well documented annotation (or XML attribute) @OnDelete on the parent (Cat, in our case) side of the association, thus:

@Entity
public class Cat {

@Id
@GeneratedValue
@Column
private Long id;

@Column
private String name;

@OneToMany(mappedBy = "parent", cascade = {CascadeType.ALL})
@ForeignKey(name = "FK_KITTEN_PARENT")
@OnDelete(action = OnDeleteAction.CASCADE)
private List<Kitten> kittens = new ArrayList<Kitten>();

This ensures that the foreign key is created with the appropriate on delete cascade clause and allowing you to safely delete your parent entities not worrying about any children that refer to them.

Follow

Get every new post delivered to your Inbox.