Can not extend directly enum [duplicate] - java

I want to take an existing enum and add more elements to it as follows:
enum A {a,b,c}
enum B extends A {d}
/*B is {a,b,c,d}*/
Is this possible in Java?

No, you can't do this in Java. Aside from anything else, d would then presumably be an instance of A (given the normal idea of "extends"), but users who only knew about A wouldn't know about it - which defeats the point of an enum being a well-known set of values.
If you could tell us more about how you want to use this, we could potentially suggest alternative solutions.

Enums represent a complete enumeration of possible values. So the (unhelpful) answer is no.
As an example of a real problem take weekdays, weekend days and, the union, days of week. We could define all days within days-of-week but then we would not be able to represent properties special to either weekdays and weekend-days.
What we could do, is have three enum types with a mapping between weekdays/weekend-days and days-of-week.
public enum Weekday {
MON, TUE, WED, THU, FRI;
public DayOfWeek toDayOfWeek() { ... }
}
public enum WeekendDay {
SAT, SUN;
public DayOfWeek toDayOfWeek() { ... }
}
public enum DayOfWeek {
MON, TUE, WED, THU, FRI, SAT, SUN;
}
Alternatively, we could have an open-ended interface for day-of-week:
interface Day {
...
}
public enum Weekday implements Day {
MON, TUE, WED, THU, FRI;
}
public enum WeekendDay implements Day {
SAT, SUN;
}
Or we could combine the two approaches:
interface Day {
...
}
public enum Weekday implements Day {
MON, TUE, WED, THU, FRI;
public DayOfWeek toDayOfWeek() { ... }
}
public enum WeekendDay implements Day {
SAT, SUN;
public DayOfWeek toDayOfWeek() { ... }
}
public enum DayOfWeek {
MON, TUE, WED, THU, FRI, SAT, SUN;
public Day toDay() { ... }
}

The recommended solution to this is the extensible enum pattern.
This involves creating an interface and using that where you currently use the enum. Then make the enum implement the interface. You can add more constants by adding an additional enum/class that also extends the interface. Here is the general idea:
public interface TrafficLights {
public abstract String getColour();
}
public enum StandardTrafficLights implements TrafficLights {
RED, YELLOW, GREEN;
public String getColour() {
return name();
}
}
public enum WeirdTrafficLights implements TrafficLights {
DOUBLE_RED;
public String getColour() {
return name();
}
}
Note that if you want something like TrafficLights.valueof(String) you will have to implement it yourself.

Under the covers your ENUM is just a regular class generated by the compiler. That generated class extends java.lang.Enum. The technical reason you can't extend the generated class is that the generated class is final. The conceptual reasons for it being final are discussed in this topic. But I'll add the mechanics to the discussion.
Here is a test enum:
public enum TEST {
ONE, TWO, THREE;
}
The resulting code from javap:
public final class TEST extends java.lang.Enum<TEST> {
public static final TEST ONE;
public static final TEST TWO;
public static final TEST THREE;
static {};
public static TEST[] values();
public static TEST valueOf(java.lang.String);
}
Conceivably you could type this class on your own and drop the "final". But the compiler prevents you from extending "java.lang.Enum" directly. You could decide NOT to extend java.lang.Enum, but then your class and its derived classes would not be an instanceof java.lang.Enum ... which might not really matter to you any way!

enum A {a,b,c}
enum B extends A {d}
/*B is {a,b,c,d}*/
can be written as:
public enum All {
a (ClassGroup.A,ClassGroup.B),
b (ClassGroup.A,ClassGroup.B),
c (ClassGroup.A,ClassGroup.B),
d (ClassGroup.B)
...
ClassGroup.B.getMembers() contains {a,b,c,d}
How it can be useful: Let say we want something like:
We have events and we are using enums. Those enums can be grouped by similar processing. If we have operation with many elements, then some events starts operation, some are just step and other end the operation. To gather such operation and avoid long switch case we can group them as in example and use:
if(myEvent.is(State_StatusGroup.START)) makeNewOperationObject()..
if(myEnum.is(State_StatusGroup.STEP)) makeSomeSeriousChanges()..
if(myEnum.is(State_StatusGroup.FINISH)) closeTransactionOrSomething()..
Example:
public enum AtmOperationStatus {
STARTED_BY_SERVER (State_StatusGroup.START),
SUCCESS (State_StatusGroup.FINISH),
FAIL_TOKEN_TIMEOUT (State_StatusGroup.FAIL,
State_StatusGroup.FINISH),
FAIL_NOT_COMPLETE (State_StatusGroup.FAIL,
State_StatusGroup.STEP),
FAIL_UNKNOWN (State_StatusGroup.FAIL,
State_StatusGroup.FINISH),
(...)
private AtmOperationStatus(StatusGroupInterface ... pList){
for (StatusGroupInterface group : pList){
group.addMember(this);
}
}
public boolean is(StatusGroupInterface with){
for (AtmOperationStatus eT : with.getMembers()){
if( eT .equals(this)) return true;
}
return false;
}
// Each group must implement this interface
private interface StatusGroupInterface{
EnumSet<AtmOperationStatus> getMembers();
void addMember(AtmOperationStatus pE);
}
// DEFINING GROUPS
public enum State_StatusGroup implements StatusGroupInterface{
START, STEP, FAIL, FINISH;
private List<AtmOperationStatus> members = new LinkedList<AtmOperationStatus>();
#Override
public EnumSet<AtmOperationStatus> getMembers() {
return EnumSet.copyOf(members);
}
#Override
public void addMember(AtmOperationStatus pE) {
members.add(pE);
}
static { // forcing initiation of dependent enum
try {
Class.forName(AtmOperationStatus.class.getName());
} catch (ClassNotFoundException ex) {
throw new RuntimeException("Class AtmEventType not found", ex);
}
}
}
}
//Some use of upper code:
if (p.getStatus().is(AtmOperationStatus.State_StatusGroup.FINISH)) {
//do something
}else if (p.getStatus().is(AtmOperationStatus.State_StatusGroup.START)) {
//do something
}
Add some more advanced:
public enum AtmEventType {
USER_DEPOSIT (Status_EventsGroup.WITH_STATUS,
Authorization_EventsGroup.USER_AUTHORIZED,
ChangedMoneyAccountState_EventsGroup.CHANGED,
OperationType_EventsGroup.DEPOSIT,
ApplyTo_EventsGroup.CHANNEL),
SERVICE_DEPOSIT (Status_EventsGroup.WITH_STATUS,
Authorization_EventsGroup.TERMINAL_AUTHORIZATION,
ChangedMoneyAccountState_EventsGroup.CHANGED,
OperationType_EventsGroup.DEPOSIT,
ApplyTo_EventsGroup.CHANNEL),
DEVICE_MALFUNCTION (Status_EventsGroup.WITHOUT_STATUS,
Authorization_EventsGroup.TERMINAL_AUTHORIZATION,
ChangedMoneyAccountState_EventsGroup.DID_NOT_CHANGED,
ApplyTo_EventsGroup.DEVICE),
CONFIGURATION_4_C_CHANGED(Status_EventsGroup.WITHOUT_STATUS,
ApplyTo_EventsGroup.TERMINAL,
ChangedMoneyAccountState_EventsGroup.DID_NOT_CHANGED),
(...)
At above if we have some fail (myEvent.is(State_StatusGroup.FAIL)) then iterating by previous events we can easily check if we must revert money transfer by:
if(myEvent2.is(ChangedMoneyAccountState_EventsGroup.CHANGED)) rollBack()..
It can be useful for:
including explicite meta-data about processing logic, less to remember
implementing some of multi-inheritance
we don't want to use class structures, ex. for sending short status messages

In case you missed it, there's a chapter in the excellent Joshua Bloch's book "Effective Java, 2nd edition".
Chapter 6 - Enums and Annotations
Item 34 : Emulate extensible enums with interfaces
Just the conclusion :
A minor disadvantage of the use of interfaces to emulate extensible enums is
those implementations cannot be inherited from one enum type to another. In the
case of our Operation example, the logic to store and retrieve the symbol associated
with an operation is duplicated in BasicOperation and ExtendedOperation.
In this case, it doesn’t matter because very little code is duplicated. If there were a
a larger amount of shared functionality, you could encapsulate it in a helper class or
a static helper method to eliminate the code duplication.
In summary, while you cannot write an extensible enum type, you can
emulate it by writing an interface to go with a basic enum type that implements
the interface. This allows clients to write their own enums that implement
the interface. These enums can then be used wherever the basic enum type can be
used, assuming APIs are written in terms of the interface.

Here is a way how I found how to extend a enum into other enum, is a very straighfoward approach:
Suposse you have a enum with common constants:
public interface ICommonInterface {
String getName();
}
public enum CommonEnum implements ICommonInterface {
P_EDITABLE("editable"),
P_ACTIVE("active"),
P_ID("id");
private final String name;
EnumCriteriaComun(String name) {
name= name;
}
#Override
public String getName() {
return this.name;
}
}
then you can try to do a manual extends in this way:
public enum SubEnum implements ICommonInterface {
P_EDITABLE(CommonEnum.P_EDITABLE ),
P_ACTIVE(CommonEnum.P_ACTIVE),
P_ID(CommonEnum.P_ID),
P_NEW_CONSTANT("new_constant");
private final String name;
EnumCriteriaComun(CommonEnum commonEnum) {
name= commonEnum.name;
}
EnumCriteriaComun(String name) {
name= name;
}
#Override
public String getName() {
return this.name;
}
}
of course every time you need to extend a constant you have to modify your SubEnum files.

This is how I enhance the enum inheritance pattern with runtime check in static initializer.
The BaseKind#checkEnumExtender checks that "extending" enum declares all the values of the base enum in exactly the same way so #name() and #ordinal() remain fully compatible.
There is still copy-paste involved for declaring values but the program fails fast if somebody added or modified a value in the base class without updating extending ones.
Common behavior for different enums extending each other:
public interface Kind {
/**
* Let's say we want some additional member.
*/
String description() ;
/**
* Standard {#code Enum} method.
*/
String name() ;
/**
* Standard {#code Enum} method.
*/
int ordinal() ;
}
Base enum, with verifying method:
public enum BaseKind implements Kind {
FIRST( "First" ),
SECOND( "Second" ),
;
private final String description ;
public String description() {
return description ;
}
private BaseKind( final String description ) {
this.description = description ;
}
public static void checkEnumExtender(
final Kind[] baseValues,
final Kind[] extendingValues
) {
if( extendingValues.length < baseValues.length ) {
throw new IncorrectExtensionError( "Only " + extendingValues.length + " values against "
+ baseValues.length + " base values" ) ;
}
for( int i = 0 ; i < baseValues.length ; i ++ ) {
final Kind baseValue = baseValues[ i ] ;
final Kind extendingValue = extendingValues[ i ] ;
if( baseValue.ordinal() != extendingValue.ordinal() ) {
throw new IncorrectExtensionError( "Base ordinal " + baseValue.ordinal()
+ " doesn't match with " + extendingValue.ordinal() ) ;
}
if( ! baseValue.name().equals( extendingValue.name() ) ) {
throw new IncorrectExtensionError( "Base name[ " + i + "] " + baseValue.name()
+ " doesn't match with " + extendingValue.name() ) ;
}
if( ! baseValue.description().equals( extendingValue.description() ) ) {
throw new IncorrectExtensionError( "Description[ " + i + "] " + baseValue.description()
+ " doesn't match with " + extendingValue.description() ) ;
}
}
}
public static class IncorrectExtensionError extends Error {
public IncorrectExtensionError( final String s ) {
super( s ) ;
}
}
}
Extension sample:
public enum ExtendingKind implements Kind {
FIRST( BaseKind.FIRST ),
SECOND( BaseKind.SECOND ),
THIRD( "Third" ),
;
private final String description ;
public String description() {
return description ;
}
ExtendingKind( final BaseKind baseKind ) {
this.description = baseKind.description() ;
}
ExtendingKind( final String description ) {
this.description = description ;
}
}

Based on #Tom Hawtin - tackline answer we add switch support,
interface Day<T> {
...
T valueOf();
}
public enum Weekday implements Day<Weekday> {
MON, TUE, WED, THU, FRI;
Weekday valueOf(){
return valueOf(name());
}
}
public enum WeekendDay implements Day<WeekendDay> {
SAT, SUN;
WeekendDay valueOf(){
return valueOf(name());
}
}
Day<Weekday> wds = Weekday.MON;
Day<WeekendDay> wends = WeekendDay.SUN;
switch(wds.valueOf()){
case MON:
case TUE:
case WED:
case THU:
case FRI:
}
switch(wends.valueOf()){
case SAT:
case SUN:
}

I tend to avoid enums, because they are not extensible. To stay with the example of the OP, if A is in a library and B in your own code, you can't extend A if it is an enum. This is how I sometimes replace enums:
// access like enum: A.a
public class A {
public static final A a = new A();
public static final A b = new A();
public static final A c = new A();
/*
* In case you need to identify your constant
* in different JVMs, you need an id. This is the case if
* your object is transfered between
* different JVM instances (eg. save/load, or network).
* Also, switch statements don't work with
* Objects, but work with int.
*/
public static int maxId=0;
public int id = maxId++;
public int getId() { return id; }
}
public class B extends A {
/*
* good: you can do like
* A x = getYourEnumFromSomeWhere();
* if(x instanceof B) ...;
* to identify which enum x
* is of.
*/
public static final A d = new A();
}
public class C extends A {
/* Good: e.getId() != d.getId()
* Bad: in different JVMs, C and B
* might be initialized in different order,
* resulting in different IDs.
* Workaround: use a fixed int, or hash code.
*/
public static final A e = new A();
public int getId() { return -32489132; };
}
There are some pits to avoid, see the comments in the code. Depending on your needs, this is a solid, extensible alternative to enums.

I suggest you take the other way around approach.
Instead of extending the existing enumeration, create a larger one and create a subset of it.
For exemple if you had an enumeration called PET and you wanted to extend it to ANIMAL you should do this instead:
public enum ANIMAL {
WOLF,CAT, DOG
}
EnumSet<ANIMAL> pets = EnumSet.of(ANIMAL.CAT, ANIMAL.DOG);
Be careful, pets is not an immutable collections, you might want to use Guava or Java9 for more safety.

As an aid to understanding why extending an Enum is not reasonable at the language implementation level to consider what would happen if you passed an instance of the extended Enum to a routine that only understands the base Enum. A switch that the compiler promised had all cases covered would in fact not cover those extended Enum values.
This further emphasizes that Java Enum values are not integers such as C's are, for instances: to use a Java Enum as an array index you must explicitly ask for its ordinal() member, to give a java Enum an arbitrary integer value you must add an explicit field for that and reference that named member.
This is not a comment on the OP's desire, just on why Java ain't never going to do it.

Having had this same problem myself I'd like to post my perspective. I think that there are a couple motivating factors for doing something like this:
You want to have some related enum codes, but in different classes. In my case I had a base class with several codes defined in an associated enum. At some later date (today!) I wanted to provide some new functionality to the base class, which also meant new codes for the enum.
The derived class would support both the base classes' enum as well as its own. No duplicate enum values! So: how to have an enum for the subclass that includes the enum's of its parent along with its new values.
Using an interface doesn't really cut it: you can accidentally get duplicate enum values. Not desirable.
I ended up just combining the enums: this ensures that there cannot be any duplicate values, at the expense of being less tightly tied to its associated class. But, I figured the duplicate issue was my main concern...

In the hopes this elegant solution of a colleague of mine is even seen in this long post I'd like to share this approach for subclassing which follows the interface approach and beyond.
Please be aware that we use custom exceptions here and this code won't compile unless you replace it with your exceptions.
The documentation is extensive and I hope it's understandable for most of you.
The interface that every subclassed enum needs to implement.
public interface Parameter {
/**
* Retrieve the parameters name.
*
* #return the name of the parameter
*/
String getName();
/**
* Retrieve the parameters type.
*
* #return the {#link Class} according to the type of the parameter
*/
Class<?> getType();
/**
* Matches the given string with this parameters value pattern (if applicable). This helps to find
* out if the given string is a syntactically valid candidate for this parameters value.
*
* #param valueStr <i>optional</i> - the string to check for
* #return <code>true</code> in case this parameter has no pattern defined or the given string
* matches the defined one, <code>false</code> in case <code>valueStr</code> is
* <code>null</code> or an existing pattern is not matched
*/
boolean match(final String valueStr);
/**
* This method works as {#link #match(String)} but throws an exception if not matched.
*
* #param valueStr <i>optional</i> - the string to check for
* #throws ArgumentException with code
* <dl>
* <dt>PARAM_MISSED</dt>
* <dd>if <code>valueStr</code> is <code>null</code></dd>
* <dt>PARAM_BAD</dt>
* <dd>if pattern is not matched</dd>
* </dl>
*/
void matchEx(final String valueStr) throws ArgumentException;
/**
* Parses a value for this parameter from the given string. This method honors the parameters data
* type and potentially other criteria defining a valid value (e.g. a pattern).
*
* #param valueStr <i>optional</i> - the string to parse the parameter value from
* #return the parameter value according to the parameters type (see {#link #getType()}) or
* <code>null</code> in case <code>valueStr</code> was <code>null</code>.
* #throws ArgumentException in case <code>valueStr</code> is not parsable as a value for this
* parameter.
*/
Object parse(final String valueStr) throws ArgumentException;
/**
* Converts the given value to its external form as it is accepted by {#link #parse(String)}. For
* most (ordinary) parameters this is simply a call to {#link String#valueOf(Object)}. In case the
* parameter types {#link Object#toString()} method does not return the external form (e.g. for
* enumerations), this method has to be implemented accordingly.
*
* #param value <i>mandatory</i> - the parameters value
* #return the external form of the parameters value, never <code>null</code>
* #throws InternalServiceException in case the given <code>value</code> does not match
* {#link #getType()}
*/
String toString(final Object value) throws InternalServiceException;
}
The implementing ENUM base class.
public enum Parameters implements Parameter {
/**
* ANY ENUM VALUE
*/
VALUE(new ParameterImpl<String>("VALUE", String.class, "[A-Za-z]{3,10}"));
/**
* The parameter wrapped by this enum constant.
*/
private Parameter param;
/**
* Constructor.
*
* #param param <i>mandatory</i> - the value for {#link #param}
*/
private Parameters(final Parameter param) {
this.param = param;
}
/**
* {#inheritDoc}
*/
#Override
public String getName() {
return this.param.getName();
}
/**
* {#inheritDoc}
*/
#Override
public Class<?> getType() {
return this.param.getType();
}
/**
* {#inheritDoc}
*/
#Override
public boolean match(final String valueStr) {
return this.param.match(valueStr);
}
/**
* {#inheritDoc}
*/
#Override
public void matchEx(final String valueStr) {
this.param.matchEx(valueStr);
}
/**
* {#inheritDoc}
*/
#Override
public Object parse(final String valueStr) throws ArgumentException {
return this.param.parse(valueStr);
}
/**
* {#inheritDoc}
*/
#Override
public String toString(final Object value) throws InternalServiceException {
return this.param.toString(value);
}
}
The subclassed ENUM which "inherits" from base class.
public enum ExtendedParameters implements Parameter {
/**
* ANY ENUM VALUE
*/
VALUE(my.package.name.VALUE);
/**
* EXTENDED ENUM VALUE
*/
EXTENDED_VALUE(new ParameterImpl<String>("EXTENDED_VALUE", String.class, "[0-9A-Za-z_.-]{1,20}"));
/**
* The parameter wrapped by this enum constant.
*/
private Parameter param;
/**
* Constructor.
*
* #param param <i>mandatory</i> - the value for {#link #param}
*/
private Parameters(final Parameter param) {
this.param = param;
}
/**
* {#inheritDoc}
*/
#Override
public String getName() {
return this.param.getName();
}
/**
* {#inheritDoc}
*/
#Override
public Class<?> getType() {
return this.param.getType();
}
/**
* {#inheritDoc}
*/
#Override
public boolean match(final String valueStr) {
return this.param.match(valueStr);
}
/**
* {#inheritDoc}
*/
#Override
public void matchEx(final String valueStr) {
this.param.matchEx(valueStr);
}
/**
* {#inheritDoc}
*/
#Override
public Object parse(final String valueStr) throws ArgumentException {
return this.param.parse(valueStr);
}
/**
* {#inheritDoc}
*/
#Override
public String toString(final Object value) throws InternalServiceException {
return this.param.toString(value);
}
}
Finally the generic ParameterImpl to add some utilities.
public class ParameterImpl<T> implements Parameter {
/**
* The default pattern for numeric (integer, long) parameters.
*/
private static final Pattern NUMBER_PATTERN = Pattern.compile("[0-9]+");
/**
* The default pattern for parameters of type boolean.
*/
private static final Pattern BOOLEAN_PATTERN = Pattern.compile("0|1|true|false");
/**
* The name of the parameter, never <code>null</code>.
*/
private final String name;
/**
* The data type of the parameter.
*/
private final Class<T> type;
/**
* The validation pattern for the parameters values. This may be <code>null</code>.
*/
private final Pattern validator;
/**
* Shortcut constructor without <code>validatorPattern</code>.
*
* #param name <i>mandatory</i> - the value for {#link #name}
* #param type <i>mandatory</i> - the value for {#link #type}
*/
public ParameterImpl(final String name, final Class<T> type) {
this(name, type, null);
}
/**
* Constructor.
*
* #param name <i>mandatory</i> - the value for {#link #name}
* #param type <i>mandatory</i> - the value for {#link #type}
* #param validatorPattern - <i>optional</i> - the pattern for {#link #validator}
* <dl>
* <dt style="margin-top:0.25cm;"><i>Note:</i>
* <dd>The default validation patterns {#link #NUMBER_PATTERN} or
* {#link #BOOLEAN_PATTERN} are applied accordingly.
* </dl>
*/
public ParameterImpl(final String name, final Class<T> type, final String validatorPattern) {
this.name = name;
this.type = type;
if (null != validatorPattern) {
this.validator = Pattern.compile(validatorPattern);
} else if (Integer.class == this.type || Long.class == this.type) {
this.validator = NUMBER_PATTERN;
} else if (Boolean.class == this.type) {
this.validator = BOOLEAN_PATTERN;
} else {
this.validator = null;
}
}
/**
* {#inheritDoc}
*/
#Override
public boolean match(final String valueStr) {
if (null == valueStr) {
return false;
}
if (null != this.validator) {
final Matcher matcher = this.validator.matcher(valueStr);
return matcher.matches();
}
return true;
}
/**
* {#inheritDoc}
*/
#Override
public void matchEx(final String valueStr) throws ArgumentException {
if (false == this.match(valueStr)) {
if (null == valueStr) {
throw ArgumentException.createEx(ErrorCode.PARAM_MISSED, "The value must not be null",
this.name);
}
throw ArgumentException.createEx(ErrorCode.PARAM_BAD, "The value must match the pattern: "
+ this.validator.pattern(), this.name);
}
}
/**
* Parse the parameters value from the given string value according to {#link #type}. Additional
* the value is checked by {#link #matchEx(String)}.
*
* #param valueStr <i>optional</i> - the string value to parse the value from
* #return the parsed value, may be <code>null</code>
* #throws ArgumentException in case the parameter:
* <ul>
* <li>does not {#link #matchEx(String)} the {#link #validator}</li>
* <li>cannot be parsed according to {#link #type}</li>
* </ul>
* #throws InternalServiceException in case the type {#link #type} cannot be handled. This is a
* programming error.
*/
#Override
public T parse(final String valueStr) throws ArgumentException, InternalServiceException {
if (null == valueStr) {
return null;
}
this.matchEx(valueStr);
if (String.class == this.type) {
return this.type.cast(valueStr);
}
if (Boolean.class == this.type) {
return this.type.cast(Boolean.valueOf(("1".equals(valueStr)) || Boolean.valueOf(valueStr)));
}
try {
if (Integer.class == this.type) {
return this.type.cast(Integer.valueOf(valueStr));
}
if (Long.class == this.type) {
return this.type.cast(Long.valueOf(valueStr));
}
} catch (final NumberFormatException e) {
throw ArgumentException.createEx(ErrorCode.PARAM_BAD, "The value cannot be parsed as "
+ this.type.getSimpleName().toLowerCase() + ".", this.name);
}
return this.parseOther(valueStr);
}
/**
* Field access for {#link #name}.
*
* #return the value of {#link #name}.
*/
#Override
public String getName() {
return this.name;
}
/**
* Field access for {#link #type}.
*
* #return the value of {#link #type}.
*/
#Override
public Class<T> getType() {
return this.type;
}
/**
* {#inheritDoc}
*/
#Override
public final String toString(final Object value) throws InternalServiceException {
if (false == this.type.isAssignableFrom(value.getClass())) {
throw new InternalServiceException(ErrorCode.PANIC,
"Parameter.toString(): Bad type of value. Expected {0} but is {1}.", this.type.getName(),
value.getClass().getName());
}
if (String.class == this.type || Integer.class == this.type || Long.class == this.type) {
return String.valueOf(value);
}
if (Boolean.class == this.type) {
return Boolean.TRUE.equals(value) ? "1" : "0";
}
return this.toStringOther(value);
}
/**
* Parse parameter values of other (non standard types). This method is called by
* {#link #parse(String)} in case {#link #type} is none of the supported standard types (currently
* String, Boolean, Integer and Long). It is intended for extensions.
* <dl>
* <dt style="margin-top:0.25cm;"><i>Note:</i>
* <dd>This default implementation always throws an InternalServiceException.
* </dl>
*
* #param valueStr <i>mandatory</i> - the string value to parse the value from
* #return the parsed value, may be <code>null</code>
* #throws ArgumentException in case the parameter cannot be parsed according to {#link #type}
* #throws InternalServiceException in case the type {#link #type} cannot be handled. This is a
* programming error.
*/
protected T parseOther(final String valueStr) throws ArgumentException, InternalServiceException {
throw new InternalServiceException(ErrorCode.PANIC,
"ParameterImpl.parseOther(): Unsupported parameter type: " + this.type.getName());
}
/**
* Convert the values of other (non standard types) to their external form. This method is called
* by {#link #toString(Object)} in case {#link #type} is none of the supported standard types
* (currently String, Boolean, Integer and Long). It is intended for extensions.
* <dl>
* <dt style="margin-top:0.25cm;"><i>Note:</i>
* <dd>This default implementation always throws an InternalServiceException.
* </dl>
*
* #param value <i>mandatory</i> - the parameters value
* #return the external form of the parameters value, never <code>null</code>
* #throws InternalServiceException in case the given <code>value</code> does not match
* {#link #getClass()}
*/
protected String toStringOther(final Object value) throws InternalServiceException {
throw new InternalServiceException(ErrorCode.PANIC,
"ParameterImpl.toStringOther(): Unsupported parameter type: " + this.type.getName());
}
}

My way to code that would be as follows:
// enum A { a, b, c }
static final Set<Short> enumA = new LinkedHashSet<>(Arrays.asList(new Short[]{'a','b','c'}));
// enum B extends A { d }
static final Set<Short> enumB = new LinkedHashSet<>(enumA);
static {
enumB.add((short) 'd');
// If you have to add more elements:
// enumB.addAll(Arrays.asList(new Short[]{ 'e', 'f', 'g', '♯', '♭' }));
}
LinkedHashSet provides both that each entry only exists once, and that their order is preserved. If order doesn’t matter, you can use HashSet instead. The following code is not possible in Java:
for (A a : B.values()) { // enum B extends A { d }
switch (a) {
case a:
case b:
case c:
System.out.println("Value is: " + a.toString());
break;
default:
throw new IllegalStateException("This should never happen.");
}
}
The code can be written as follows:
for (Short a : enumB) {
switch (a) {
case 'a':
case 'b':
case 'c':
System.out.println("Value is: " + new String(Character.toChars(a)));
break;
default:
throw new IllegalStateException("This should never happen.");
}
}
From Java 7 onwards you can even do the same with String:
// enum A { BACKWARDS, FOREWARDS, STANDING }
static final Set<String> enumA = new LinkedHashSet<>(Arrays.asList(new String[] {
"BACKWARDS", "FOREWARDS", "STANDING" }));
// enum B extends A { JUMP }
static final Set<String> enumB = new LinkedHashSet<>(enumA);
static {
enumB.add("JUMP");
}
Using the enum replacement:
for (String a : enumB) {
switch (a) {
case "BACKWARDS":
case "FOREWARDS":
case "STANDING":
System.out.println("Value is: " + a);
break;
default:
throw new IllegalStateException("This should never happen.");
}
}

Related

How to override a method from a class existing in an external jar?

I added an external dependency (open CSV) to my Gradle project. I wanted to override a particular method from that.
I subclassed the required class in a new custom class
But I can not override any methods in the super class. Even though they are public
What will be the reason for this.? The Gradle dependencies exist in Library/Project and External Dependencies.
class CustomMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {
private static final String[] HEADER = new String[]{"TradeID", "GWML GUID", "MXML GUID", "GWML File", "MxML File", "MxML Counterparty", "GWML Counterparty"};
#Override //This is not working
public String[] generateHeader() {
return HEADER;
}
}
The super class looks like:
package com.opencsv.bean;
import com.opencsv.CSVReader;
import com.opencsv.ICSVParser;
import com.opencsv.exceptions.CsvBadConverterException;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
/**
* Allows for the mapping of columns with their positions. Using this strategy
* without annotations ({#link com.opencsv.bean.CsvBindByPosition} or
* {#link com.opencsv.bean.CsvCustomBindByPosition}) requires all the columns
* to be present in the CSV file and for them to be in a particular order. Using
* annotations allows one to specify arbitrary zero-based column numbers for
* each bean member variable to be filled. Also this strategy requires that the
* file does NOT have a header. That said, the main use of this strategy is
* files that do not have headers.
*
* #param <T> Type of object that is being processed.
*/
public class ColumnPositionMappingStrategy<T> extends AbstractMappingStrategy<String, Integer, ComplexFieldMapEntry<String, Integer, T>, T> {
/**
* Whether the user has programmatically set the map from column positions
* to field names.
*/
private boolean columnsExplicitlySet = false;
/**
* The map from column position to {#link BeanField}.
*/
private FieldMapByPosition<T> fieldMap;
/**
* Holds a {#link java.util.Comparator} to sort columns on writing.
*/
private Comparator<Integer> writeOrder;
/**
* Used to store a mapping from presumed input column index to desired
* output column index, as determined by applying {#link #writeOrder}.
*/
private Integer[] columnIndexForWriting = null;
/**
* Default constructor.
*/
public ColumnPositionMappingStrategy() {
}
/**
* There is no header per se for this mapping strategy, but this method
* checks the first line to determine how many fields are present and
* adjusts its field map accordingly.
*/
// The rest of the Javadoc is inherited
#Override
public void captureHeader(CSVReader reader) throws IOException {
// Validation
if (type == null) {
throw new IllegalStateException(ResourceBundle
.getBundle(ICSVParser.DEFAULT_BUNDLE_NAME, errorLocale)
.getString("type.unset"));
}
String[] firstLine = reader.peek();
fieldMap.setMaxIndex(firstLine.length - 1);
if (!columnsExplicitlySet) {
headerIndex.clear();
for (FieldMapByPositionEntry entry : fieldMap) {
Field f = entry.getField().getField();
if (f.getAnnotation(CsvCustomBindByPosition.class) != null
|| f.getAnnotation(CsvBindAndSplitByPosition.class) != null
|| f.getAnnotation(CsvBindAndJoinByPosition.class) != null
|| f.getAnnotation(CsvBindByPosition.class) != null) {
headerIndex.put(entry.getPosition(), f.getName().toUpperCase().trim());
}
}
}
}
/**
* #return {#inheritDoc} For this mapping strategy, it's simply
* {#code index} wrapped as an {#link java.lang.Integer}.
*/
// The rest of the Javadoc is inherited
#Override
protected Object chooseMultivaluedFieldIndexFromHeaderIndex(int index) {
return Integer.valueOf(index);
}
#Override
public BeanField<T> findField(int col) {
// If we have a mapping for changing the order of the columns on
// writing, be sure to use it.
if (columnIndexForWriting != null) {
return col < columnIndexForWriting.length ? fieldMap.get(columnIndexForWriting[col]) : null;
}
return fieldMap.get(col);
}
/**
* This method returns an empty array.
* The column position mapping strategy assumes that there is no header, and
* thus it also does not write one, accordingly.
*
* #return An empty array
*/
// The rest of the Javadoc is inherited
#Override
public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
String[] h = super.generateHeader(bean);
columnIndexForWriting = new Integer[h.length];
// Once we support Java 8, this might be nicer with Arrays.parallelSetAll().
for (int i = 0; i < columnIndexForWriting.length; i++) {
columnIndexForWriting[i] = i;
}
// Create the mapping for input column index to output column index.
Arrays.sort(columnIndexForWriting, writeOrder);
return ArrayUtils.EMPTY_STRING_ARRAY;
}
/**
* Gets a column name.
*
* #param col Position of the column.
* #return Column name or null if col > number of mappings.
*/
#Override
public String getColumnName(int col) {
return headerIndex.getByPosition(col);
}
/**
* Retrieves the column mappings.
*
* #return String array with the column mappings.
*/
public String[] getColumnMapping() {
return headerIndex.getHeaderIndex();
}
/**
* Setter for the column mapping.
* This mapping is for reading. Use of this method in conjunction with
* writing is undefined.
*
* #param columnMapping Column names to be mapped.
*/
public void setColumnMapping(String... columnMapping) {
if (columnMapping != null) {
headerIndex.initializeHeaderIndex(columnMapping);
} else {
headerIndex.clear();
}
columnsExplicitlySet = true;
}
#Override
protected void loadFieldMap() throws CsvBadConverterException {
boolean required;
fieldMap = new FieldMapByPosition<>(errorLocale);
fieldMap.setColumnOrderOnWrite(writeOrder);
for (Field field : loadFields(getType())) {
String fieldLocale, capture, format;
// Custom converters always have precedence.
if (field.isAnnotationPresent(CsvCustomBindByPosition.class)) {
CsvCustomBindByPosition annotation = field
.getAnnotation(CsvCustomBindByPosition.class);
Class<? extends AbstractBeanField> converter = annotation.converter();
BeanField<T> bean = instantiateCustomConverter(converter);
bean.setField(field);
required = annotation.required();
bean.setRequired(required);
fieldMap.put(annotation.position(), bean);
}
// Then check for a collection
else if (field.isAnnotationPresent(CsvBindAndSplitByPosition.class)) {
CsvBindAndSplitByPosition annotation = field.getAnnotation(CsvBindAndSplitByPosition.class);
required = annotation.required();
fieldLocale = annotation.locale();
String splitOn = annotation.splitOn();
String writeDelimiter = annotation.writeDelimiter();
Class<? extends Collection> collectionType = annotation.collectionType();
Class<?> elementType = annotation.elementType();
Class<? extends AbstractCsvConverter> splitConverter = annotation.converter();
capture = annotation.capture();
format = annotation.format();
CsvConverter converter = determineConverter(field, elementType, fieldLocale, splitConverter);
fieldMap.put(annotation.position(), new BeanFieldSplit<T>(
field, required, errorLocale, converter, splitOn,
writeDelimiter, collectionType, capture, format));
}
// Then check for a multi-column annotation
else if (field.isAnnotationPresent(CsvBindAndJoinByPosition.class)) {
CsvBindAndJoinByPosition annotation = field.getAnnotation(CsvBindAndJoinByPosition.class);
required = annotation.required();
fieldLocale = annotation.locale();
Class<?> elementType = annotation.elementType();
Class<? extends MultiValuedMap> mapType = annotation.mapType();
Class<? extends AbstractCsvConverter> joinConverter = annotation.converter();
capture = annotation.capture();
format = annotation.format();
CsvConverter converter = determineConverter(field, elementType, fieldLocale, joinConverter);
fieldMap.putComplex(annotation.position(), new BeanFieldJoinIntegerIndex<T>(
field, required, errorLocale, converter, mapType, capture, format));
}
// Then it must be a bind by position.
else {
CsvBindByPosition annotation = field.getAnnotation(CsvBindByPosition.class);
required = annotation.required();
fieldLocale = annotation.locale();
capture = annotation.capture();
format = annotation.format();
CsvConverter converter = determineConverter(field, field.getType(), fieldLocale, null);
fieldMap.put(annotation.position(), new BeanFieldSingleValue<T>(
field, required, errorLocale, converter, capture, format));
}
}
}
#Override
public void verifyLineLength(int numberOfFields) throws CsvRequiredFieldEmptyException {
if (!headerIndex.isEmpty()) {
BeanField f;
StringBuilder sb = null;
for (int i = numberOfFields; i <= headerIndex.findMaxIndex(); i++) {
f = findField(i);
if (f != null && f.isRequired()) {
if (sb == null) {
sb = new StringBuilder(ResourceBundle.getBundle(ICSVParser.DEFAULT_BUNDLE_NAME, errorLocale).getString("multiple.required.field.empty"));
}
sb.append(' ');
sb.append(f.getField().getName());
}
}
if (sb != null) {
throw new CsvRequiredFieldEmptyException(type, sb.toString());
}
}
}
private List<Field> loadFields(Class<? extends T> cls) {
List<Field> fields = new LinkedList<>();
for (Field field : FieldUtils.getAllFields(cls)) {
if (field.isAnnotationPresent(CsvBindByPosition.class)
|| field.isAnnotationPresent(CsvCustomBindByPosition.class)
|| field.isAnnotationPresent(CsvBindAndJoinByPosition.class)
|| field.isAnnotationPresent(CsvBindAndSplitByPosition.class)) {
fields.add(field);
}
}
setAnnotationDriven(!fields.isEmpty());
return fields;
}
/**
* Returns the column position for the given column number.
* Yes, they're the same thing. For this mapping strategy, it's a simple
* conversion from an integer to a string.
*/
// The rest of the Javadoc is inherited
#Override
public String findHeader(int col) {
return Integer.toString(col);
}
#Override
protected FieldMap<String, Integer, ? extends ComplexFieldMapEntry<String, Integer, T>, T> getFieldMap() {
return fieldMap;
}
/**
* Sets the {#link java.util.Comparator} to be used to sort columns when
* writing beans to a CSV file.
* Behavior of this method when used on a mapping strategy intended for
* reading data from a CSV source is not defined.
*
* #param writeOrder The {#link java.util.Comparator} to use. May be
* {#code null}, in which case the natural ordering is used.
* #since 4.3
*/
public void setColumnOrderOnWrite(Comparator<Integer> writeOrder) {
this.writeOrder = writeOrder;
if (fieldMap != null) {
fieldMap.setColumnOrderOnWrite(this.writeOrder);
}
}
}
Have you tried
public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
super.generateHeader(bean);
return HEADER;
}

java.util.ArrayList cannot be cast to java.lang.Comparable

I have UniversalComparator and it does all the task related to sorting, It uses reflection API to recognized the method name and invocatio target.
Now what happened is, I need to sort the sites, previously it was sorted using "name", now what happened is, user need to upload documents in frequency of monthly, quarterly,semi and annually.
REQUIREMENT
If document not uploaded in any of the frequency, that data represent with white color, rest of the blocks are reprsented as red color.
There are six SITES right now,
first site has only one white block
second site has no white block.
third site has no white block
four has three white block
fifth has three white block
sixth has three white block
so the count is
1
0
0
3
3
Now whta I did, I cretaed an ArrayList of Integer and store all the count
now I need to sort the list of SITE Block on behalf of this count so it should be like
0
0
1
3
3
CODE
package com.lear.common.utility;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Comparator;
public class UniversalComparator implements Comparator {
/**
* static final int ASCENDING
*/
public static final int ASCENDING = 1;
/**
* static final int DESCENDING
*/
public static final int DESCENDING = -1;
/*
* int for descAscIndicator
*/
private int descAscIndicator = 1;
/*
* String to store method Name
*/
private String methodName = "toString";
/**
* Constructor for UniversalComparator
*
* #param descAscIndicator
* int to store descAscIndicator.
*/
public UniversalComparator(int descAscIndicator) {
this.descAscIndicator = descAscIndicator;
}
/**
* Constructor for UniversalComparator
*
* #param methodName
* : name of method as criteria
* #param descAscIndicator
* : order of sorting
*/
public UniversalComparator(String methodName, int descAscIndicator) {
this(descAscIndicator);
this.methodName = methodName;
}
/**
* This Method compare Two Objects
*
* #param o1
* : An Instance of Object.
* #param o2
* : An Instance of Object.
* #return int
*/
public int compare(Object o1, Object o2) {
Object comp1 = null;
Object comp2 = null;
try {
Method o1_Method = (o1.getClass()).getMethod(methodName, null);
Method o2_Method = (o2.getClass()).getMethod(methodName, null);
comp1 = o1_Method.invoke(o1, null);
comp2 = o2_Method.invoke(o2, null);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Method does not exist" + e.getMessage());
} catch (IllegalAccessException e) {
throw new RuntimeException("Illegal access" + e.getMessage());
} catch (InvocationTargetException e) {
throw new RuntimeException("InvocationTargetException"
+ e.getMessage());
}
Comparable c1 = (Comparable) comp1;
Comparable c2 = (Comparable) comp2;
return c1.compareTo(c2) * descAscIndicator;
}
/**
* Check for Equality obect
*
* #param obj
* : An Instance of Object.
* #return boolean return true if equal or false if not
*/
public boolean equals(Object obj) {
return this.equals(obj);
}
}
ScoreCardManager.java
List<Integer> naSiteDataList = new ArrayList<Integer>();
public String getComparativeSiteAnalysis(Integer divId, String lang, int selectedYear) {
// PLENTY OF CODE HERE
int annualDataCount = site.getComparativeColorAnnual().equalsIgnoreCase("White") ? 1 : 0;
naSiteDataCount = monthlyDataCount + quaterlyDataCount + semiAnnualDataCount + annualDataCount;
naSiteDataList.add(naSiteDataCount);
naSiteCounter.add(naSiteDataCount);
site.setNaSiteCount(naSiteDataList);
site.setNaSiteCounter(naSiteCounter);
System.out.println("datacount is" + naSiteDataCount);
}
// THIS LINE
Collections.sort(sites, new UniversalComparator("getNaSiteCount", 1));
Site.java
public class Site{
// lot of properties
private List<Integer> naSiteCount;
public List<Integer> getNaSiteCount() {
return naSiteCount;
}
public void setNaSiteCount(List<Integer> naSiteCount) {
this.naSiteCount = naSiteCount;
}
}
Reflection is a really awful approach to this. You have absolutely no type safety in this code. You have no guarantee that a method with the name you supply as a string actually exists. You have no guarantee that it takes no arguments. You have no idea what exceptions it might throw.
If you were working in Java 8 plus, it would be trivial to implement specific comparators:
Comparator<Object> comparator = Comparator.comparing(Object::toString);
but the lack of Java 8 features isn't a reason to do it with reflection.
Define an abstract class:
abstract class AbstractComparator<T, C extends Comparable<? super C>> implements Comparator<T> {
abstract C toComparable(T object);
#Override public int compare(T a, T b) {
return toComparable(a).compareTo(toComparable(b));
}
Comparator<T> reverse() {
return new Comparator<T>() {
#Override public int compare(T a, T b) {
return toComparable(b).compareTo(toComparable(a));
}
}
}
}
and then implement this for your specific cases:
Comparator<Object> comparator = new AbstractComparator<Object, String> {
#Override String toComparable(Object object) { return object.toString(); }
}.reverse();
If you are using Guava or some other library with a Function-like class, or are happy to define it yourself, you can of course take a compositional approach, rather than using inheritance:
Comparator<Object> comparator = new ConcreteComparator<>(new Function<Object, String>() {
#Override public String apply(Object object) {
return object.toString();
}
});
Provided you don't use raw types around either the comparator or the things you are comparing, ClassCastExceptions will now be impossible.

How to change values in the SET Method

I am starting to develop my skills in JAVA, however I have a doubt.
I'm creating an object in JAVA, created the constructor and so on, then, it asks "Change the AGE_RECENT value from 1 to 3", I initially declared this as final because I never thought it would change, so no SET or GET were created. I am wondering how can I change the value from 1 to 3 in the SET Method.
I have this variable
private static int AGE_RECENT=1;
I did this.
public void setAgeRecent() {
Vehicle.AGE_RECENT = 3;
}
It works if you run the program, it changes the variable's value, however nothing was declared in that method as every SET method.
Just wondering how can I do this. If this is correct, good, if not, thanks for helping!
As someone asked, the code.
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package tp1;
/**
*
* #author Nelson
*/
public class Vehicle {
/** Variáveis da classe, têm como função **/
private String registration;
private int registrationYear;
private double consumption;
private double autonomy;
private int cilinderCapacity;
/**
* Final variables. They are final because they do not suffer any kind of modification during the project.
* YEAR_OMISSION is 2016 because the currect year is 2016.
* ENVIRONMENTAL_CHARGE_OMISSION is 0.10(10 cents), gave this value because there is nothing to mention the
especific value, hence why I gave 0.10.
* RATING_RECENT = Is a string, just has the text "RECENT" inside.
* RATING_COMTEMPORY - Another string, just with the "Comtempory" text inside.
* RATING_CLASSIC - Yet again another string, with the "Classic" text.
* AGE_RECENT - It is to help to compare if a vehicle is recent or not, it has the value 3.
* AGE_CLASSIC - It is to again help to compare, value is 20.
*/
private static final int YEAR_OMISSION = 2016;
private static final double ENVIRONMENTAL_CHARGE_OMISSION=0.10;
private static final String RATING_RECENT="Recent";
private static final String RATING_CONTEMPORY="Contempory";
private static final String RATING_CLASSIC="Classic";
private static int AGE_RECENT=1;
private static final int AGE_CLASSIC=20;
/**
* Constructor of the object, it has the Registration
* #param registration
* #param registrationYear - The year the vehicle was first registered.
* #param consumption - How many liters the vehicle consumes.
* #param autonomy - How many KMs a vehicle can go without refuelling.
* #param cilinderCapacity - How many Cubic Inches the engine has.
*/
public Vehicle(String registration,int registrationYear, double consumption, double autonomy, int cilinderCapacity) {
this.registration = registration;
this.registrationYear = registrationYear;
this.consumption = consumption;
this.autonomy = autonomy;
this.cilinderCapacity = cilinderCapacity;
}
/**
* Null Constructor, it has no values, they will be attributed in the MAIN Class.
*/
public Vehicle() {
this.registration = "";
this.registrationYear = 0;
this.consumption = 0;
this.autonomy = 0;
this.cilinderCapacity =0;
this.registrationYear = YEAR_OMISSION;
}
/**
* Copy Constructor.
*/
public Vehicle(Vehicle vehicle) {
this.registration = vehicle.getRegistration();
this.registrationYear = vehicle.getRegistrationYear();
this.consumption = vehicle.getConsumption();
this.autonomy = vehicle.getAutonomy();
this.cilinderCapacity = vehicle.getCilinderCapacity();
}
public String getRegistration() {
return registration;
}
public int getRegistrationYear() {
return registrationYear;
}
public double getConsumption() {
return consumption;
}
public double getAutonomy() {
return autonomy;
}
public int getCilinderCapacity() {
return cilinderCapacity;
}
public double getYearRecent() {
return AGE_RECENT;
}
public double getAgeRecent(){
return AGE_RECENT;
}
public void setRegistration(String registration) {
this.registration = registration;
}
public void setRegistrationYear(int registrationYear) {
this.registrationYear = registrationYear;
}
public void setConsumption(double consumption) {
this.consumption = consumption;
}
public void setAutonomy(double autonomy) {
this.autonomy = autonomy;
}
public void setCilinderCapacity(int cilinderCapacity) {
this.cilinderCapacity = cilinderCapacity;
}
public void setAgeRecent() {
Vehicle.AGE_RECENT = 3;
}
/**
* Calculate the age of the vehicle to compare in the vehicleRating method
* #return The year, which is 2016 minus the year the vehicle was first registered.
*/
private int calculateAge(){
return YEAR_OMISSION-this.registrationYear;
}
/**
* Calculate the Circulation Tax.
* #return Returns the value of the Environmental Charge multiplied by the Cilinder Capacity of the vehicle.
*/
public double calculateCirculationTax(){
return ENVIRONMENTAL_CHARGE_OMISSION*cilinderCapacity;
}
/**
* Classify the vehicle based on the age.
* If the result given by the calculateAge method is minor than the AGE_RECENT variable(3), then it will
return "Recent"
* If the result is between Age_RECENT and AGE_CLASSIC(20), then it will say "Contemporary"
* If none of the IFs apply, it will return "Classic".
**/
public static String vehicleRating(Vehicle vehicle) {
if(vehicle.calculateAge() < Vehicle.AGE_RECENT) {
return Vehicle.RATING_RECENT; }
else if ((vehicle.calculateAge()>=Vehicle.AGE_RECENT)&&(vehicle.calculateAge()<=Vehicle.AGE_CLASSIC)){
return Vehicle.RATING_CONTEMPORY;}
else
return Vehicle.RATING_CLASSIC;
}
#Override
public String toString() {
return "Vehicle{" + "registration=" + registration + ", registrationYear=" + registrationYear + ", consumption=" + consumption + ", autonomy=" + autonomy + ", cilinderCapacity=" + cilinderCapacity + '}';
}
}
A setter that takes no arguments is simply a method, not a setter. In order to work as a setter a method must take a parameter that matches the type of the value being set - in your case, that would be int:
public static void setAgeRecent(int age) {
AGE_RECENT = age;
}
Note a few things here:
Since AGE_RECENT is static, setAgeRecent should be static
Since AGE_RECENT and setAgeRecent are static members of the same class Vehicle, you do not need to qualify AGE_RECENT with Vehicle
Now users of your class would be able to call your static setter as follows:
Vehicle.setAgeRecent(3);
A static varible, or class variable, may be used without the need to create an instance of that class. But its value may be changed freely at runtime.
A final variable is not a variable in a true sense, because it's value can't be changed at runtime.
Thus, you may have a set method for a static variable, but never to a final variable.

Nice way to convert AxisDatatypes from the same .xsd

I am looking for a possibility to convert two Axis Datatypes (generated by WSDL2Java) into each other. Both DataTypes consists of exactly the same Attributes because they are both from the same XSD.
The Problem is Axis generates them as Seperated Datatypes.
DataType1:
public static class AbstractAsynchronousResponse extends AbstractResponse implements org.apache.axis2.databinding.ADBBean {
/*
* This type was generated from the piece of schema that had name =
* AbstractAsynchronousResponse Namespace URI =
* http://www.example.org/AllCallbackTypes Namespace Prefix = ns2
*/
.........}
DataType2:
public static class AbstractAsynchronousResponse extends AbstractResponse implements org.apache.axis2.databinding.ADBBean {
/*
* This type was generated from the piece of schema that had name =
* AbstractAsynchronousResponse Namespace URI =
* http://www.example.org/AllCallbackTypes Namespace Prefix = ns2
*/
.........}
Now I want to do Something like this:
AbstractAsynchronousResponse1 response1 = new AbstractAsynchronousResponse1();
AbstractAsynchronousResponse2 response2 = (AbstractAsynchronousResponse2) response1;
Is there a solution?
Here is a Method I created to solve this Problem. However this isn't really nice but it works.
/**
* This will cast an {#link ADBBean} implementation to another
* {#link ADBBean}, but the Implementation will be a subClass of
* <b>parentLocationOfSourceClass</b>.<br>
* This only is possible because of the structure of all ADBBean
* implementations created by <code>Axis2 ADB-Databinding</code>. If you
* cange the Databinding you probably have to adapt this Method.
*
* #param inputADBBean
* An ADBBean Implementation created by
* <code>Axis2 ADB-Databinding</code>
* #param parentLocationOfSourceClass
* This is meant to be the <code>ClientStub</code> Class created
* by <code>Axis2 ADB-Databinding</code>. The Implementation of
* the <code>inputADBBean</code> has to be available with the
* same name in the <code>ClientStub</code>
* #return An {#link ADBBean} implementation defined as SubClass of the
* <code>ClientStub</code> Class created by
* <code>Axis2 ADB-Databinding</code>
* #throws Exception
*/
public static ADBBean castADBBean(ADBBean inputADBBean, String parentLocationOfSourceClass) throws Exception {
Class clazz = CallbackResponsePoolClient.getClassForParentLocation(inputADBBean, parentLocationOfSourceClass);
ADBBean outputADBBean = CallbackResponsePoolClient.getInstanceForADBBean(clazz);
for (Method method : outputADBBean.getClass().getMethods()) {
String methodName = method.getName();
if (methodName.startsWith("set")) {
CallbackResponsePoolClient.logger.debug("Found a setter: " + methodName);
String getterName = methodName.replaceFirst("set", "get");
Object arg = inputADBBean.getClass().getMethod(getterName).invoke(inputADBBean);
// We need to check if arg lives in the namespace:
// org.example.www.callbackresponsepoolinterface
// This will happen if we have nested Objects. E.g.
// EndpointType inside of EndpointResponse
// TODO: instanceof ADBBean could lead to problems, maybe
// sometimes we don't want to cast an ADBBean, but I can't think
// a scenario right now
if (arg instanceof ADBBean) {
arg = CallbackResponsePoolClient.castADBBean((ADBBean) arg, parentLocationOfSourceClass);
}
// We also need to handle Arrays of ADBBeans. See above
if (arg instanceof ADBBean[]) {
Class innputClass = ((ADBBean[]) arg).getClass().getComponentType();
// Better Create a new Object, because arg[0], can get you
// an Exception for an empty Array
ADBBean inputArrObj = CallbackResponsePoolClient.getInstanceForADBBean(innputClass);
Class outputArrClass = CallbackResponsePoolClient.getClassForParentLocation(inputArrObj, parentLocationOfSourceClass);
Object outputArray = Array.newInstance(outputArrClass, ((ADBBean[]) arg).length);
for (int i = 0; i < Array.getLength(arg); i++) {
Array.set(outputArray, i, CallbackResponsePoolClient.castADBBean((ADBBean) Array.get(arg, i), parentLocationOfSourceClass));
}
arg = outputArray;
}
method.invoke(outputADBBean, arg);
}
}
return outputADBBean;
}
private static Class getClassForParentLocation(ADBBean inputADBBean, String parentLocationOfSourceClass) throws ClassNotFoundException {
return Class.forName(parentLocationOfSourceClass + "$" + inputADBBean.getClass().getSimpleName());
}
private static ADBBean getInstanceForADBBean(Class clazz) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Constructor constructor = clazz.getConstructor();
return (ADBBean) constructor.newInstance();
}

CodePro Analytix - I don't get the Audit rule "Variable Has Null Value"

I'm testing CodePro Anlaytix (Eclipse plug-in) to check for code style in a project.
CPA tells me that "Variable has null value" for the variable "titleParam" and "descParam" in the setters.
Here's the class:
/**
* fdas fsda fsda fsa
* #version 1.0
*/
public class CodeProItem {
/**
* Field title.
*/
private String title;
/**
* Field desc.
*/
private String desc;
/**
* Method getTitle.
* #return String
*/
public String getTitle() {
return title;
}
/**
* Method setTitle.
* #param titleParam String
*/
public void setTitle(String titleParam) {
this.title = titleParam;
}
/**
* Method getDesc.
* #return String
*/
public String getDesc() {
return desc;
}
/**
* Method setDesc.
* #param descParam String
*/
public void setDesc(String descParam) {
this.desc = descParam;
}
}
Here's the summary of the rule (from CPA doc):
A variable that is guaranteed to have a null value and is used in an
expression may indicate that the programmer forgot to initialize
variable with its actual value.
The rule "Variable has null value" is activated and this is an example of code that would be caught by this rule (from CPA doc):
public boolean myMethod(String param)
{
String tmp = null;
if (tmp.equals(param)) {
return true;
} else {
return false;
}
}
I get the example, but why does it say that my parameters in the setters are null?
It seems like a bug for me. If it would say it might be null and should be checked, that is possible. But unless it is called with a known null value somewhere else (that is possible and often possible to find out statically), the error makes no sense. However, if the caller provides the issue, then simply the error marker is misplaced.
Generally, I use FindBugs - that is optimized not to give false warnings, but works quite nice in my experience.

Categories