I have several types of data-sources, that I would like to use for additional XML validation and providing auto-completion (using Eclipse if possible).
This source could be some other XML (from another or the same file):
<type name="TypeA"/>
<type name="TypeB"/>
or a Java-class
public List<String> getValues() {
return Arrays.asList("Val1", "Val2", "Val3");
}
These values are then referenced in other XML-files:
<x type="TypeA" value="Val2" />
<x type="TypeB" value="Val3" />
Now I would like to improve editing this file by
Validating the XML-File
(underline wrong types/values, if possible display a red x in Package Expl.)
Providing code-completion
(suggest TypeA and TypeB when typing type=")
I'll certainly have to write some code, but what is the best way start?
Can the standard XML-Editor be extended?
Are there any plugins that can help? (Maybe Rinzo XML Editor?)
Any other options that I did not think of?
You can write XSD schemas for your XML files, then Eclipse can validate them.
There are, for sure, frameworks who generate XSD schemas from your Java classes.
Check the answers here: utility to generate xsd from java class
If you decide extending Rinzo, it seems documentation has bee updated on how to extend the same features you'll like to customize :)
http://editorxml.sourceforge.net/extendingRinzo.html
Peter,
I answer you in a new post since I didn't have enough space in a comment.
If you want to extend Rinzo according to your example I guess you'll need to create a plugin contributing the extension points declared in the site's documentation.
For the content assistant implementation I guess a rough implementation based on your examples could be as follow:
public class CustomSourceAssistProcessor implements IXMLContentAssistProcessor {
#Override
public void addAttributeValuesProposals(XMLNode currentNode, String attributeName, String prefix,
ITextViewer viewer, int offset, Collection<ICompletionProposal> results) {
if("x".equals(currentNode.getTagName()) && "type".equals(attributeName)) {
for (String possibleValue : this.getPossibleValuesFromXML()) {
results.add(new CompletionProposal(possibleValue, offset, prefix.length(), 0, null, "Proposal Description...", null, null));
}
}
if("x".equals(currentNode.getTagName()) && "value".equals(attributeName)) {
for (String possibleValue : this.getPossibleValuesFromJavaClass()) {
results.add(new CompletionProposal(possibleValue, offset, prefix.length(), 0, null, "Proposal Description...", null, null));
}
}
}
}
That's as far as interacting with Rinzo's API, and your particular logic to gather values either from an external XML file or java-class should be implemented in the methods getPossibleValuesFromXML() and getPossibleValuesFromJavaClass()
On the other hand in order to add your custom validator I guess the rough implementation of your extension point, also based on your example, should be similar to this one:
public class CustomSourceXMLValidator implements XmlValidator {
#Override
public void validate(RinzoXMLEditor editor) {
editor.getModel().getTree().accept(new HierarchicalVisitor() {
#Override
public boolean visitStart(XMLNode node) {
if(node.isTag() && "x".equals(node.getTagName())) {
for (Entry<String, XMLAttribute> entry : node.getAttributes().entrySet()) {
if("type".equals(entry.getKey())) {
this.validateValueFromXML(entry.getValue().getValue());
}
if("value".equals(entry.getKey())) {
this.valdateValueFromJavaClass(entry.getValue().getValue());
}
}
}
return true;
}
private void valdateValueFromJavaClass(XMLAttribute xmlAttribute) {
if(!this.getPossibleValuesFromXML().contains(xmlAttribute.getValue())) {
this.createMarker(editor, xmlAttribute);
}
}
private void validateValueFromXML(XMLAttribute xmlAttribute) {
if(!this.getPossibleValuesFromJavaClass().contains(xmlAttribute.getValue())) {
this.createMarker(editor, xmlAttribute);
}
}
});
}
}
And once again it's up to you the implementation of the methods getPossibleValuesFromXML() and getPossibleValuesFromJavaClass().
You can also see the source code of ClassNamesValidatorVisitor as an example.
Keep on rockin' in the free world! :)
I'm pretty sure eclipse already does both these things but they are part of one of the extended packages. Try downloading eclipse for Java EE developers. I'm fairly sure validation and completetion are part of the Web Tools Platform.
Check Here For Validating XML
Related
This question already has answers here:
Long list of if statements in Java
(15 answers)
Closed 4 years ago.
My code here detects if the mimeType is equals to some MIME type, if it is, it will do a certain conversion
public void convertToMp3(File src, File target,String mimeType){
if(mimeType.equals("audio/mpeg")){
...
}else if(mimeType.equals("audio/wav")){
mp3ToWav();
}else if(mimeType.equals("audio/ogg")){
...
}else if(...){
... //More if and else here
}
I have shortened my code, because it has a lot of else if statements, What design pattern is suitable for removing many if and else or else if statements?
You could have a Converter interface. Then you could create a class for each Mimetype like:
public interface Converter {
public void convertToMp3();
public void convertToOgg();
}
public class MpegConverter implements Converter {
public void convertToMp3() {
//Code here
}
public void convertToOgg() {
//Code here
}
}
You would need a class like this for each converter. Then you could set up a map like this:
Map<String, Converter> mimeTypeMap = new HashMap<String, Converter>();
mimeTypeMap.put("audio/mpeg", new MpegConverter());
Then your convertToMp3 method becomes like this:
Converter converter = mimeTypeMap.get(mimeType);
converter.convertToMp3();
Using this approach you could easily add different converters in the future.
All untested, probably doesn't compile, but you get the idea
If you use pre-JDK7, you may add an enum for all MIME types:
public static enum MimeTypes {
MP3, WAV, OGG
}
public class Stuff {
...
switch (MimeTypes.valueOf(mimeType)) {
case MP3: handleMP3(); break;
case WAV: handleWAV(); break;
case OGG: handleOGG(); break;
}
}
And have a look at the Stack Overflow question Java - Convert String to enum on how to convert Strings to enums.
Consider using the Strategy design pattern and a Map to dispatch to the appropriate strategy. Particularly useful if you you will need additional functionality, in addition to a conversion for a particular mimeType, or the convertors are large and complicated code and you would want to place each convertor in its own .java file.
interface Convertor {
void convert(File src, File target);
}
private static void convertWav(File src, File target) {
...
}
...
private static final Map< String, Convertor > convertors = new ...;
static {
convertors.put("audio/wav", new Convertor {
void convert(File src, File target) {
convertWav(src, target);
}
});
convertors.put("audio/ogg", new Convertor {
void convert(File src, File target) {
convertOgg(src, target);
}
});
...
}
public void convertToMp3(File src, File target, String mimeType){
final Convertor convertor = convertors.get(mimeType);
if (convertor == null ) {
...
} else {
convertor.convert(src, target);
}
}
If you run the same methods for each case you should check State pattern
If you are using JDK 7, you can use switch-case construct:
See: Why can't I switch on a String?
For prior versions, if-else is the only choice.
It's definitely a Strategy design pattern. But you have a big problem in your general design. It's not a good programming habit to use String to identify a type. Simply because it's easily editable and you can make a grammar mistake and spend all the afternoon looking for a programming mistake. You can avoid using map<>.
I suggest the following:
Extend class File. The new class adds a new attribute FileType and a new method convertTo(FileType) to class File. This attribute holds its type: “audio” , “wav”... and again don't use String, Use Enum. In this case I called it FileType. Extend File as much as you want: WavFile, AudioFile...
Use a Strategy dp to create your converters.
Use a Factory dp to initialize the converters.
Since every File knows its own type and the target type (use convertTo() method to specify the target type) it will call the factory to get the correct Converter automatically!!!
This design is scalable and you can add as much as you need FileType and converters.
The answer you vote for is misleading!!!!
There is a big difference between coding and hacking.
If you are not using Java 7 you could create an enum and use that value with a switch case. You then only need to pass the enum value (rather than a file, I don't why you are doing that). It would look neater too.
These should help with what you want to do:
[Java Enum Examples][1] -
[Java Switch Case examples][2]
I was recently asked on a coding interview to write a simple Java console app that does some file io and displays the data. I was going to go to town with a DAO but since I never manipulate the data past a read, the entire idea of a DAO seems overkill.
Anyone know a clean way to ensure separation of concern without the weight of full CRUD when you don't need it ?
Looks like standard MVC pattern. Your console is the view, the code that reads file is the controller and the code that captures file line or whole file content is your model.
You can further simplify it as View and Model where model will encapsulate both file reading and wrapping its content into Java class.
How about Martin Fowler's Table Gateway pattern, explained here. Just include the find (Read) methods and miss create, insert, and update.
you can simply refer Command /Query pattern ,where commands are one which perform create update and delete operation seperately and Queries are introduce to read only purpose .
hence you implement what you need and left the others
This question was in interview so there was not much time for detailed design, As a minimum fulfillment of above concerns, following structure will provide flexibility. details could be filled as per the requirements.
public interface IODevice {
String read();
void write(String data);
}
class FileIO implements IODevice {
#Override
public String read() {
return null;
}
#Override
public void write(String data) {
//...;
}
}
class ConsoleIO implements IODevice {
#Override
public String read() {
return null;
}
#Override
public void write(String data) {
//... null;
}
}
public class DataConverter {
public static void main(String[] args) {
FileIO fData1 = null;// ... appropriately obtained instance;
FileIO fData2 = null;// ... appropriately obtained instance;
ConsoleIO cData = null;// ... appropriately obtained instance;
cData.write(fData2.read());
fData1.write(cData.read());
}
}
The client class uses only APIs of the devices. This will keep option of extending interface to implement new device wrapper (e.g. xml, stream etc)
This question already has answers here:
Long list of if statements in Java
(15 answers)
Closed 4 years ago.
My code here detects if the mimeType is equals to some MIME type, if it is, it will do a certain conversion
public void convertToMp3(File src, File target,String mimeType){
if(mimeType.equals("audio/mpeg")){
...
}else if(mimeType.equals("audio/wav")){
mp3ToWav();
}else if(mimeType.equals("audio/ogg")){
...
}else if(...){
... //More if and else here
}
I have shortened my code, because it has a lot of else if statements, What design pattern is suitable for removing many if and else or else if statements?
You could have a Converter interface. Then you could create a class for each Mimetype like:
public interface Converter {
public void convertToMp3();
public void convertToOgg();
}
public class MpegConverter implements Converter {
public void convertToMp3() {
//Code here
}
public void convertToOgg() {
//Code here
}
}
You would need a class like this for each converter. Then you could set up a map like this:
Map<String, Converter> mimeTypeMap = new HashMap<String, Converter>();
mimeTypeMap.put("audio/mpeg", new MpegConverter());
Then your convertToMp3 method becomes like this:
Converter converter = mimeTypeMap.get(mimeType);
converter.convertToMp3();
Using this approach you could easily add different converters in the future.
All untested, probably doesn't compile, but you get the idea
If you use pre-JDK7, you may add an enum for all MIME types:
public static enum MimeTypes {
MP3, WAV, OGG
}
public class Stuff {
...
switch (MimeTypes.valueOf(mimeType)) {
case MP3: handleMP3(); break;
case WAV: handleWAV(); break;
case OGG: handleOGG(); break;
}
}
And have a look at the Stack Overflow question Java - Convert String to enum on how to convert Strings to enums.
Consider using the Strategy design pattern and a Map to dispatch to the appropriate strategy. Particularly useful if you you will need additional functionality, in addition to a conversion for a particular mimeType, or the convertors are large and complicated code and you would want to place each convertor in its own .java file.
interface Convertor {
void convert(File src, File target);
}
private static void convertWav(File src, File target) {
...
}
...
private static final Map< String, Convertor > convertors = new ...;
static {
convertors.put("audio/wav", new Convertor {
void convert(File src, File target) {
convertWav(src, target);
}
});
convertors.put("audio/ogg", new Convertor {
void convert(File src, File target) {
convertOgg(src, target);
}
});
...
}
public void convertToMp3(File src, File target, String mimeType){
final Convertor convertor = convertors.get(mimeType);
if (convertor == null ) {
...
} else {
convertor.convert(src, target);
}
}
If you run the same methods for each case you should check State pattern
If you are using JDK 7, you can use switch-case construct:
See: Why can't I switch on a String?
For prior versions, if-else is the only choice.
It's definitely a Strategy design pattern. But you have a big problem in your general design. It's not a good programming habit to use String to identify a type. Simply because it's easily editable and you can make a grammar mistake and spend all the afternoon looking for a programming mistake. You can avoid using map<>.
I suggest the following:
Extend class File. The new class adds a new attribute FileType and a new method convertTo(FileType) to class File. This attribute holds its type: “audio” , “wav”... and again don't use String, Use Enum. In this case I called it FileType. Extend File as much as you want: WavFile, AudioFile...
Use a Strategy dp to create your converters.
Use a Factory dp to initialize the converters.
Since every File knows its own type and the target type (use convertTo() method to specify the target type) it will call the factory to get the correct Converter automatically!!!
This design is scalable and you can add as much as you need FileType and converters.
The answer you vote for is misleading!!!!
There is a big difference between coding and hacking.
If you are not using Java 7 you could create an enum and use that value with a switch case. You then only need to pass the enum value (rather than a file, I don't why you are doing that). It would look neater too.
These should help with what you want to do:
[Java Enum Examples][1] -
[Java Switch Case examples][2]
How does one go about and try to find all subclasses of a given class (or all implementors of a given interface) in Java?
As of now, I have a method to do this, but I find it quite inefficient (to say the least).
The method is:
Get a list of all class names that exist on the class path
Load each class and test to see if it is a subclass or implementor of the desired class or interface
In Eclipse, there is a nice feature called the Type Hierarchy that manages to show this quite efficiently.
How does one go about and do it programmatically?
Scanning for classes is not easy with pure Java.
The spring framework offers a class called ClassPathScanningCandidateComponentProvider that can do what you need. The following example would find all subclasses of MyClass in the package org.example.package
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AssignableTypeFilter(MyClass.class));
// scan in org.example.package
Set<BeanDefinition> components = provider.findCandidateComponents("org/example/package");
for (BeanDefinition component : components)
{
Class cls = Class.forName(component.getBeanClassName());
// use class cls found
}
This method has the additional benefit of using a bytecode analyzer to find the candidates which means it will not load all classes it scans.
There is no other way to do it other than what you described. Think about it - how can anyone know what classes extend ClassX without scanning each class on the classpath?
Eclipse can only tell you about the super and subclasses in what seems to be an "efficient" amount of time because it already has all of the type data loaded at the point where you press the "Display in Type Hierarchy" button (since it is constantly compiling your classes, knows about everything on the classpath, etc).
This is not possible to do using only the built-in Java Reflections API.
A project exists that does the necessary scanning and indexing of your classpath so you can get access this information...
Reflections
A Java runtime metadata analysis, in the spirit of Scannotations
Reflections scans your classpath, indexes the metadata, allows you to query it on runtime and may save and collect that information for many modules within your project.
Using Reflections you can query your metadata for:
get all subtypes of some type
get all types annotated with some annotation
get all types annotated with some annotation, including annotation parameters matching
get all methods annotated with some
(disclaimer: I have not used it, but the project's description seems to be an exact fit for your needs.)
Try ClassGraph. (Disclaimer, I am the author). ClassGraph supports scanning for subclasses of a given class, either at runtime or at build time, but also much more. ClassGraph can build an abstract representation of the entire class graph (all classes, annotations, methods, method parameters, and fields) in memory, for all classes on the classpath, or for classes in selected packages, and you can query this class graph however you want. ClassGraph supports more classpath specification mechanisms and classloaders than any other scanner, and also works seamlessly with the new JPMS module system, so if you base your code on ClassGraph, your code will be maximally portable. See the API here.
Don't forget that the generated Javadoc for a class will include a list of known subclasses (and for interfaces, known implementing classes).
I know I'm a few years late to this party, but I came across this question trying to solve the same problem. You can use Eclipse's internal searching programatically, if you're writing an Eclipse Plugin (and thus take advantage of their caching, etc), to find classes which implement an interface. Here's my (very rough) first cut:
protected void listImplementingClasses( String iface ) throws CoreException
{
final IJavaProject project = <get your project here>;
try
{
final IType ifaceType = project.findType( iface );
final SearchPattern ifacePattern = SearchPattern.createPattern( ifaceType, IJavaSearchConstants.IMPLEMENTORS );
final IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
final SearchEngine searchEngine = new SearchEngine();
final LinkedList<SearchMatch> results = new LinkedList<SearchMatch>();
searchEngine.search( ifacePattern,
new SearchParticipant[]{ SearchEngine.getDefaultSearchParticipant() }, scope, new SearchRequestor() {
#Override
public void acceptSearchMatch( SearchMatch match ) throws CoreException
{
results.add( match );
}
}, new IProgressMonitor() {
#Override
public void beginTask( String name, int totalWork )
{
}
#Override
public void done()
{
System.out.println( results );
}
#Override
public void internalWorked( double work )
{
}
#Override
public boolean isCanceled()
{
return false;
}
#Override
public void setCanceled( boolean value )
{
}
#Override
public void setTaskName( String name )
{
}
#Override
public void subTask( String name )
{
}
#Override
public void worked( int work )
{
}
});
} catch( JavaModelException e )
{
e.printStackTrace();
}
}
The first problem I see so far is that I'm only catching classes which directly implement the interface, not all their subclasses - but a little recursion never hurt anyone.
I did this several years ago. The most reliable way to do this (i.e. with official Java APIs and no external dependencies) is to write a custom doclet to produce a list that can be read at runtime.
You can run it from the command line like this:
javadoc -d build -doclet com.example.ObjectListDoclet -sourcepath java/src -subpackages com.example
or run it from ant like this:
<javadoc sourcepath="${src}" packagenames="*" >
<doclet name="com.example.ObjectListDoclet" path="${build}"/>
</javadoc>
Here's the basic code:
public final class ObjectListDoclet {
public static final String TOP_CLASS_NAME = "com.example.MyClass";
/** Doclet entry point. */
public static boolean start(RootDoc root) throws Exception {
try {
ClassDoc topClassDoc = root.classNamed(TOP_CLASS_NAME);
for (ClassDoc classDoc : root.classes()) {
if (classDoc.subclassOf(topClassDoc)) {
System.out.println(classDoc);
}
}
return true;
}
catch (Exception ex) {
ex.printStackTrace();
return false;
}
}
}
For simplicity, I've removed command line argument parsing and I'm writing to System.out rather than a file.
Keeping in mind the limitations mentioned in the other answers, you can also use openpojo's PojoClassFactory (available on Maven) in the following manner:
for(PojoClass pojoClass : PojoClassFactory.enumerateClassesByExtendingType(packageRoot, Superclass.class, null)) {
System.out.println(pojoClass.getClazz());
}
Where packageRoot is the root String of the packages you wish to search in (e.g. "com.mycompany" or even just "com"), and Superclass is your supertype (this works on interfaces as well).
Depending on your particular requirements, in some cases Java's service loader mechanism might achieve what you're after.
In short, it allows developers to explicitly declare that a class subclasses some other class (or implements some interface) by listing it in a file in the JAR/WAR file's META-INF/services directory. It can then be discovered using the java.util.ServiceLoader class which, when given a Class object, will generate instances of all the declared subclasses of that class (or, if the Class represents an interface, all the classes implementing that interface).
The main advantage of this approach is that there is no need to manually scan the entire classpath for subclasses - all the discovery logic is contained within the ServiceLoader class, and it only loads the classes explicitly declared in the META-INF/services directory (not every class on the classpath).
There are, however, some disadvantages:
It won't find all subclasses, only those that are explicitly declared. As such, if you need to truly find all subclasses, this approach may be insufficient.
It requires the developer to explicitly declare the class under the META-INF/services directory. This is an additional burden on the developer, and can be error-prone.
The ServiceLoader.iterator() generates subclass instances, not their Class objects. This causes two issues:
You don't get any say on how the subclasses are constructed - the no-arg constructor is used to create the instances.
As such, the subclasses must have a default constructor, or must explicity declare a no-arg constructor.
Apparently Java 9 will be addressing some of these shortcomings (in particular, the ones regarding instantiation of subclasses).
An Example
Suppose you're interested in finding classes that implement an interface com.example.Example:
package com.example;
public interface Example {
public String getStr();
}
The class com.example.ExampleImpl implements that interface:
package com.example;
public class ExampleImpl implements Example {
public String getStr() {
return "ExampleImpl's string.";
}
}
You would declare the class ExampleImpl is an implementation of Example by creating a file META-INF/services/com.example.Example containing the text com.example.ExampleImpl.
Then, you could obtain an instance of each implementation of Example (including an instance of ExampleImpl) as follows:
ServiceLoader<Example> loader = ServiceLoader.load(Example.class)
for (Example example : loader) {
System.out.println(example.getStr());
}
// Prints "ExampleImpl's string.", plus whatever is returned
// by other declared implementations of com.example.Example.
It should be noted as well that this will of course only find all those subclasses that exist on your current classpath. Presumably this is OK for what you are currently looking at, and chances are you did consider this, but if you have at any point released a non-final class into the wild (for varying levels of "wild") then it is entirely feasible that someone else has written their own subclass that you will not know about.
Thus if you happened to be wanting to see all subclasses because you want to make a change and are going to see how it affects subclasses' behaviour - then bear in mind the subclasses that you can't see. Ideally all of your non-private methods, and the class itself should be well-documented; make changes according to this documentation without changing the semantics of methods/non-private fields and your changes should be backwards-compatible, for any subclass that followed your definition of the superclass at least.
The reason you see a difference between your implementation and Eclipse is because you scan each time, while Eclipse (and other tools) scan only once (during project load most of the times) and create an index. Next time you ask for the data it doesn't scan again, but look at the index.
I'm using a reflection lib, which scans your classpath for all subclasses: https://github.com/ronmamo/reflections
This is how it would be done:
Reflections reflections = new Reflections("my.project");
Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);
You can use org.reflections library and then, create an object of Reflections class. Using this object, you can get list of all subclasses of given class.
https://www.javadoc.io/doc/org.reflections/reflections/0.9.10/org/reflections/Reflections.html
Reflections reflections = new Reflections("my.project.prefix");
System.out.println(reflections.getSubTypesOf(A.class)));
Add them to a static map inside (this.getClass().getName()) the parent classes constructor (or create a default one) but this will get updated in runtime. If lazy initialization is an option you can try this approach.
I just write a simple demo to use the org.reflections.Reflections to get subclasses of abstract class:
https://github.com/xmeng1/ReflectionsDemo
I needed to do this as a test case, to see if new classes had been added to the code. This is what I did
final static File rootFolder = new File(SuperClass.class.getProtectionDomain().getCodeSource().getLocation().getPath());
private static ArrayList<String> files = new ArrayList<String>();
listFilesForFolder(rootFolder);
#Test(timeout = 1000)
public void testNumberOfSubclasses(){
ArrayList<String> listSubclasses = new ArrayList<>(files);
listSubclasses.removeIf(s -> !s.contains("Superclass.class"));
for(String subclass : listSubclasses){
System.out.println(subclass);
}
assertTrue("You did not create a new subclass!", listSubclasses.size() >1);
}
public static void listFilesForFolder(final File folder) {
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
listFilesForFolder(fileEntry);
} else {
files.add(fileEntry.getName().toString());
}
}
}
If you intend to load all subclassess of given class which are in the same package, you can do so:
public static List<Class> loadAllSubClasses(Class pClazz) throws IOException, ClassNotFoundException {
ClassLoader classLoader = pClazz.getClassLoader();
assert classLoader != null;
String packageName = pClazz.getPackage().getName();
String dirPath = packageName.replace(".", "/");
Enumeration<URL> srcList = classLoader.getResources(dirPath);
List<Class> subClassList = new ArrayList<>();
while (srcList.hasMoreElements()) {
File dirFile = new File(srcList.nextElement().getFile());
File[] files = dirFile.listFiles();
if (files != null) {
for (File file : files) {
String subClassName = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);
if (! subClassName.equals(pClazz.getName())) {
subClassList.add(Class.forName(subClassName));
}
}
}
}
return subClassList;
}
find all classes in classpath
public static List<String> getClasses() {
URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
List<String> classes = new ArrayList<>();
for (URL url : urlClassLoader.getURLs()) {
try {
if (url.toURI().getScheme().equals("file")) {
File file = new File(url.toURI());
if (file.exists()) {
try {
if (file.isDirectory()) {
for (File listFile : FileUtils.listFiles(file, new String[]{"class"}, true)) {
String classFile = listFile.getAbsolutePath().replace(file.getAbsolutePath(), "").replace(".class", "");
if (classFile.startsWith(File.separator)) {
classFile = classFile.substring(1);
}
classes.add(classFile.replace(File.separator, "."));
}
} else {
JarFile jarFile = new JarFile(file);
if (url.getFile().endsWith(".jar")) {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
if (jarEntry.getName().endsWith(".class")) {
classes.add(jarEntry.getName().replace(".class", "").replace("/", "."));
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
return classes;
}
enter link description hereService Manager in java will get all implementing classes for an interface in J
This question already has answers here:
Long list of if statements in Java
(15 answers)
Closed 4 years ago.
My code here detects if the mimeType is equals to some MIME type, if it is, it will do a certain conversion
public void convertToMp3(File src, File target,String mimeType){
if(mimeType.equals("audio/mpeg")){
...
}else if(mimeType.equals("audio/wav")){
mp3ToWav();
}else if(mimeType.equals("audio/ogg")){
...
}else if(...){
... //More if and else here
}
I have shortened my code, because it has a lot of else if statements, What design pattern is suitable for removing many if and else or else if statements?
You could have a Converter interface. Then you could create a class for each Mimetype like:
public interface Converter {
public void convertToMp3();
public void convertToOgg();
}
public class MpegConverter implements Converter {
public void convertToMp3() {
//Code here
}
public void convertToOgg() {
//Code here
}
}
You would need a class like this for each converter. Then you could set up a map like this:
Map<String, Converter> mimeTypeMap = new HashMap<String, Converter>();
mimeTypeMap.put("audio/mpeg", new MpegConverter());
Then your convertToMp3 method becomes like this:
Converter converter = mimeTypeMap.get(mimeType);
converter.convertToMp3();
Using this approach you could easily add different converters in the future.
All untested, probably doesn't compile, but you get the idea
If you use pre-JDK7, you may add an enum for all MIME types:
public static enum MimeTypes {
MP3, WAV, OGG
}
public class Stuff {
...
switch (MimeTypes.valueOf(mimeType)) {
case MP3: handleMP3(); break;
case WAV: handleWAV(); break;
case OGG: handleOGG(); break;
}
}
And have a look at the Stack Overflow question Java - Convert String to enum on how to convert Strings to enums.
Consider using the Strategy design pattern and a Map to dispatch to the appropriate strategy. Particularly useful if you you will need additional functionality, in addition to a conversion for a particular mimeType, or the convertors are large and complicated code and you would want to place each convertor in its own .java file.
interface Convertor {
void convert(File src, File target);
}
private static void convertWav(File src, File target) {
...
}
...
private static final Map< String, Convertor > convertors = new ...;
static {
convertors.put("audio/wav", new Convertor {
void convert(File src, File target) {
convertWav(src, target);
}
});
convertors.put("audio/ogg", new Convertor {
void convert(File src, File target) {
convertOgg(src, target);
}
});
...
}
public void convertToMp3(File src, File target, String mimeType){
final Convertor convertor = convertors.get(mimeType);
if (convertor == null ) {
...
} else {
convertor.convert(src, target);
}
}
If you run the same methods for each case you should check State pattern
If you are using JDK 7, you can use switch-case construct:
See: Why can't I switch on a String?
For prior versions, if-else is the only choice.
It's definitely a Strategy design pattern. But you have a big problem in your general design. It's not a good programming habit to use String to identify a type. Simply because it's easily editable and you can make a grammar mistake and spend all the afternoon looking for a programming mistake. You can avoid using map<>.
I suggest the following:
Extend class File. The new class adds a new attribute FileType and a new method convertTo(FileType) to class File. This attribute holds its type: “audio” , “wav”... and again don't use String, Use Enum. In this case I called it FileType. Extend File as much as you want: WavFile, AudioFile...
Use a Strategy dp to create your converters.
Use a Factory dp to initialize the converters.
Since every File knows its own type and the target type (use convertTo() method to specify the target type) it will call the factory to get the correct Converter automatically!!!
This design is scalable and you can add as much as you need FileType and converters.
The answer you vote for is misleading!!!!
There is a big difference between coding and hacking.
If you are not using Java 7 you could create an enum and use that value with a switch case. You then only need to pass the enum value (rather than a file, I don't why you are doing that). It would look neater too.
These should help with what you want to do:
[Java Enum Examples][1] -
[Java Switch Case examples][2]