Skip to content

Commit

Permalink
added two exceptions, made change of platform available in some cases.
Browse files Browse the repository at this point in the history
  • Loading branch information
glelouet committed Jan 20, 2020
1 parent be84c54 commit 9573ae7
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 45 deletions.
44 changes: 30 additions & 14 deletions src/main/java/com/helger/jcodemodel/JCodeModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;

import com.helger.jcodemodel.exceptions.JInvalidFileNameException;
import com.helger.jcodemodel.exceptions.JCaseSensitivityChangeException;
import com.helger.jcodemodel.meta.CodeModelBuildingException;
import com.helger.jcodemodel.meta.ErrorTypeFound;
import com.helger.jcodemodel.meta.JCodeModelJavaxLangModelAdapter;
Expand Down Expand Up @@ -240,21 +242,27 @@ public final IFileSystemConvention getFileSystemConvention ()
* The file system convention to be used. May not be
* <code>null</code>.
* @return this for chaining
* @throws JCodeModelException
* if a package or a resource directory is already present.
* @throws JCaseSensitivityChangeException
* if the new convention has different case sensitivity
* @throws JInvalidFileNameException
* if the new convention does not allow some file previously
* created.
* @see IFileSystemConvention
* @since 3.4.0
*/
@Nonnull
public final IFileSystemConvention setFileSystemConvention(@Nonnull final IFileSystemConvention aFSConvention)
throws JCodeModelException
throws JCaseSensitivityChangeException, JInvalidFileNameException
{
JCValueEnforcer.notNull(aFSConvention, "FSConvention");
if (aFSConvention == m_aFSConvention) {
return m_aFSConvention;
}
IFileSystemConvention old = m_aFSConvention;
JCValueEnforcer.notNull (aFSConvention, "FSConvention");
if (!m_aResourceDirs.isEmpty()) {
// test null in case we set the platform from the constructor
if (m_aFSConvention != null && m_aFSConvention.isCaseSensistive() != aFSConvention.isCaseSensistive()) {
throw new JCodeModelException ("The FileSystem convention cannot be changed case sensitivity if a package or a resource directory already exists.");
throw new JCaseSensitivityChangeException();
}
for (FSName name : m_aResourceDirs.keySet()) {
String sName = name.getName();
Expand All @@ -265,8 +273,7 @@ public final IFileSystemConvention setFileSystemConvention(@Nonnull final IFileS
if (sName.length() > 0) {
for (final String sPart : JCStringHelper.getExplodedArray(JResourceDir.SEPARATOR, sName)) {
if (!aFSConvention.isValidDirectoryName(sPart)) {
throw new IllegalArgumentException("Resource directory name '" + sName
+ "' contains the the invalid part '" + sPart + "' according to the current file system conventions");
throw new JInvalidFileNameException(sName, sPart);
}
}
}
Expand Down Expand Up @@ -365,16 +372,20 @@ private FSName _createFSName (@Nonnull final String sName)
* be generated
*
* @param sName
* Name of the resource directory. Use "" to indicate the root
* directory.
* Name of the resource directory. Use "" to indicate the root
* directory.
* @return Newly generated resource directory. Never <code>null</code>.
* @throws JCodeModelException
* If the resource directory could not be created because another
* @throws JInvalidFileNameException
* if the name is invalid for current platform.
* @throws JResourceAlreadyExistsException
* If the resource directory could not be created because another
* file or class already has this name.
* @see #rootResourceDir()
* @since v3.4.0
*/
@Nonnull
public JResourceDir resourceDir (@Nonnull final String sName) throws JCodeModelException
public JResourceDir resourceDir(@Nonnull final String sName)
throws JResourceAlreadyExistsException, JInvalidFileNameException
{
JCValueEnforcer.notNull (sName, "Name");

Expand Down Expand Up @@ -407,8 +418,13 @@ public JResourceDir resourceDir (@Nonnull final String sName) throws JCodeModelE

// Get main subdir
final JResourceDir aFinalParentDir = aParentDir;
aCur = m_aResourceDirs.computeIfAbsent (_createFSName (sDirName),
k -> new JResourceDir (this, aFinalParentDir, k.getName ()));
FSName curName = _createFSName(sDirName);
// cannot use computeifAbsent because exception thrown.
aCur = m_aResourceDirs.get(curName);
if (aCur == null) {
aCur = new JResourceDir(this, aFinalParentDir, curName.getName());
m_aResourceDirs.put(curName, aCur);
}
aParentDir = aCur;
}

Expand Down
77 changes: 46 additions & 31 deletions src/main/java/com/helger/jcodemodel/JResourceDir.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.helger.jcodemodel.exceptions.JInvalidFileNameException;
import com.helger.jcodemodel.fmt.AbstractJResourceFile;
import com.helger.jcodemodel.util.FSName;
import com.helger.jcodemodel.util.JCFilenameHelper;
Expand Down Expand Up @@ -88,48 +89,50 @@ public class JResourceDir implements IJOwned
* Constructor
*
* @param aOwner
* The code writer being used to create this package. May not be
* <code>null</code>.
* The code writer being used to create this package. May not be
* <code>null</code>.
* @param aParentDir
* The parent directory. May only be <code>null</code> for the target
* root resource directory. In that case the name must be "".
* The parent directory. May only be <code>null</code> for the target
* root resource directory. In that case the name must be "".
* @param sName
* Name of directory. May not be <code>null</code> but empty. No
* absolute paths are allowed and only Linux forward slashes may be
* used as path separators.
* @throws IllegalArgumentException
* If each part of the package name is not a valid filename part.
* Name of directory. May not be <code>null</code> but empty. No
* absolute paths are allowed and only Linux forward slashes may be
* used as path separators.
* @throws JInvalidFileNameException
* If a part of the package name is not a valid filename part.
*/
protected JResourceDir (@Nonnull final JCodeModel aOwner,
@Nullable final JResourceDir aParentDir,
@Nonnull final String sName)
@Nullable final JResourceDir aParentDir,
@Nonnull final String sName) throws JInvalidFileNameException
{
JCValueEnforcer.notNull (sName, "Name");
JCValueEnforcer.notNull (aOwner, "CodeModel");
if (aParentDir == null)
if (aParentDir == null) {
JCValueEnforcer.isTrue (sName.length () == 0, "If no parent directory is provided, the name must be empty");
if (sName.length () == 0)
}
if (sName.length () == 0) {
JCValueEnforcer.isNull (aParentDir, "If no name is provided, the parent directory must be null");
}

m_aOwner = aOwner;
m_aParentDir = aParentDir;
m_sName = sName;

// An empty directory name is okay
if (sName.length () > 0)
for (final String sPart : JCStringHelper.getExplodedArray (JResourceDir.SEPARATOR, sName))
if (!aOwner.getFileSystemConvention ().isValidDirectoryName (sPart))
throw new IllegalArgumentException ("Resource directory name '" +
sName +
"' contains the the invalid part '" +
sPart +
"' according to the current file system conventions");
if (sName.length () > 0) {
for (final String sPart : JCStringHelper.getExplodedArray (JResourceDir.SEPARATOR, sName)) {
if (!aOwner.getFileSystemConvention ().isValidDirectoryName (sPart)) {
throw new JInvalidFileNameException(sName, sPart);
}
}
}
}

/**
* @return the code model root object being used to create this resource
* directory.
*/
@Override
@Nonnull
public final JCodeModel owner ()
{
Expand Down Expand Up @@ -164,8 +167,9 @@ public JResourceDir parent ()
@Nonnull
private FSName _createFSName (@Nonnull final String sName)
{
if (m_aOwner.getFileSystemConvention ().isCaseSensistive ())
if (m_aOwner.getFileSystemConvention ().isCaseSensistive ()) {
return FSName.createCaseSensitive (sName);
}
return FSName.createCaseInsensitive (sName);
}

Expand Down Expand Up @@ -193,27 +197,31 @@ public <T extends AbstractJResourceFile> T addResourceFile (@Nonnull final T aRe

final String sName = aResFile.name ();

if (!m_aOwner.getFileSystemConvention ().isValidFilename (sName))
if (!m_aOwner.getFileSystemConvention ().isValidFilename (sName)) {
throw new IllegalArgumentException ("Resource filename '" +
sName +
"' is invalid according to the current file system conventions");
sName +
"' is invalid according to the current file system conventions");
}

// Check if a sub directory already exists with the same name
if (m_aOwner.containsResourceDir (fullChildName (sName)))
if (m_aOwner.containsResourceDir (fullChildName (sName))) {
throw new JResourceAlreadyExistsException (fullChildName (sName));
}

// Check filename uniqueness
final FSName aKey = _createFSName (sName);
if (m_aResources.containsKey (aKey))
if (m_aResources.containsKey (aKey)) {
throw new JResourceAlreadyExistsException (fullChildName (sName));
}

// Check if a Java class with the same name already exists
if (JCStringHelper.endsWithCaseInsensitive (sName, ".java"))
{
// Cut trailing ".java"
final JDefinedClass aDC = _getMatchingPackage ()._getClass (sName.substring (0, sName.length () - 5));
if (aDC != null)
if (aDC != null) {
throw new JClassAlreadyExistsException (aDC);
}
}

// All checks good - add to map
Expand Down Expand Up @@ -269,16 +277,18 @@ public List <AbstractJResourceFile> getAllResourceFiles ()
public JResourceDir subDir (@Nonnull final String sSubDirName) throws JCodeModelException
{
// Check if a file with the same name already exists
if (hasResourceFile (sSubDirName))
if (hasResourceFile (sSubDirName)) {
throw new JResourceAlreadyExistsException (fullChildName (sSubDirName));
}

// Check if a Java class with the same name already exists
if (JCStringHelper.endsWithCaseInsensitive (sSubDirName, ".java"))
{
// Cut trailing ".java"
final JDefinedClass aDC = _getMatchingPackage ()._getClass (sSubDirName.substring (0, sSubDirName.length () - 5));
if (aDC != null)
if (aDC != null) {
throw new JClassAlreadyExistsException (aDC);
}
}

return owner ().resourceDir (isUnnamed () ? sSubDirName : m_sName + SEPARATOR + sSubDirName);
Expand Down Expand Up @@ -318,6 +328,11 @@ String fullChildName (@Nonnull final String sChildName)
@Nonnull
static JResourceDir root (@Nonnull final JCodeModel aOwner)
{
return new JResourceDir (aOwner, null, "");
try {
return new JResourceDir(aOwner, null, "");
} catch (JInvalidFileNameException e) {
// should not happen
throw new UnsupportedOperationException("catch this", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.helger.jcodemodel.exceptions;

import com.helger.jcodemodel.JCodeModelException;

public class JCaseSensitivityChangeException extends JCodeModelException {

/**
*
*/
private static final long serialVersionUID = 1L;

public JCaseSensitivityChangeException() {
super(
"The FileSystem convention cannot be changed for one with a different case sensitivity if a package or a resource directory already exists.");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.helger.jcodemodel.exceptions;

import com.helger.jcodemodel.JCodeModelException;

/**
* called when trying to create a new file with a name that is not accepted by
* target platform.
*
*/
public class JInvalidFileNameException extends JCodeModelException {

/**
*
*/
private static final long serialVersionUID = 1L;

public JInvalidFileNameException(String fileName) {
super("invalid file name : " + fileName);
}

public JInvalidFileNameException(String fullName, String part) {
super("Resource name '" + fullName + "' contains the the invalid part '" + part
+ "' according to the current file system conventions");
}

}
73 changes: 73 additions & 0 deletions src/test/java/com/helger/jcodemodel/JCodeModelTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,18 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;

import java.nio.charset.StandardCharsets;
import java.util.Map;

import org.junit.Assert;
import org.junit.Test;

import com.helger.jcodemodel.exceptions.JInvalidFileNameException;
import com.helger.jcodemodel.exceptions.JCaseSensitivityChangeException;
import com.helger.jcodemodel.fmt.JTextFile;
import com.helger.jcodemodel.util.CodeModelTestsHelper;
import com.helger.jcodemodel.util.EFileSystemConvention;
import com.helger.jcodemodel.util.IFileSystemConvention;

/**
* @author Kohsuke Kawaguchi
Expand Down Expand Up @@ -133,4 +140,70 @@ public void testIssue71v2 () throws Exception
cl.method (JMod.PUBLIC, cm.VOID, "call").param (cm.ref (Long.class), "obj");
CodeModelTestsHelper.parseCodeModel (cm);
}

@Test
public void testChangePlatform() throws JCodeModelException {
JCodeModel cm = JCodeModel.createUnified();

cm._class(JMod.PUBLIC, "my.Precious");
try {
// should fail, the package "my" is translated to a dir.
cm.setFileSystemConvention(EFileSystemConvention.WINDOWS);
Assert.fail();
} catch (JCaseSensitivityChangeException jcsce) {
// correct
}

cm = JCodeModel.createUnified();
cm.resourceDir("my").addResourceFile(JTextFile.createFully("File1", StandardCharsets.UTF_8, "bla"));
try {
// should fail, because the windows FS is not case sensitive.
cm.setFileSystemConvention(EFileSystemConvention.WINDOWS);
Assert.fail();
} catch (JCaseSensitivityChangeException jcsce) {
// correct
}

// should pass, accept any resource name
cm.setFileSystemConvention(new IFileSystemConvention() {

@Override
public boolean isValidFilename(String sPath) {
return true;
}

@Override
public boolean isValidDirectoryName(String sPath) {
return true;
}

@Override
public boolean isCaseSensistive() {
return true;
}
});
try {
// should fail, existing dir "my" and file "File1" are not accepted.
cm.setFileSystemConvention(new IFileSystemConvention() {

@Override
public boolean isValidFilename(String sPath) {
return false;
}

@Override
public boolean isValidDirectoryName(String sPath) {
return false;
}

@Override
public boolean isCaseSensistive() {
return true;
}
});
Assert.fail();
} catch (JInvalidFileNameException ifne) {
// correct
}
}
}

0 comments on commit 9573ae7

Please sign in to comment.